source: rtems/cpukit/libnetworking/net/radix.c @ cb68253

5
Last change on this file since cb68253 was cb68253, checked in by Sebastian Huber <sebastian.huber@…>, on 09/07/18 at 04:19:02

network: Use kernel/user space header files

Add and use <machine/rtems-bsd-kernel-space.h> and
<machine/rtems-bsd-user-space.h> similar to the libbsd to avoid command
line defines and defines scattered throught the code base.

Simplify cpukit/libnetworking/Makefile.am.

Update #3375.

  • Property mode set to 100644
File size: 27.0 KB
Line 
1#include <machine/rtems-bsd-kernel-space.h>
2
3/*
4 * Copyright (c) 1988, 1989, 1993
5 *      The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 *      @(#)radix.c     8.5 (Berkeley) 5/19/95
32 * $FreeBSD: src/sys/net/radix.c,v 1.36 2004/04/21 15:27:36 luigi Exp $
33 */
34
35#ifdef HAVE_CONFIG_H
36#include "config.h"
37#endif
38
39/*
40 * Routines to build and maintain radix trees for routing lookups.
41 */
42#ifndef _RADIX_H_
43#include <sys/param.h>
44#ifdef  _KERNEL
45#include <sys/systm.h>
46#include <sys/malloc.h>
47#define M_DONTWAIT M_NOWAIT
48#include <sys/domain.h>
49#else
50#include <stdlib.h>
51#endif
52#include <sys/syslog.h>
53#include <net/radix.h>
54#endif
55
56static int      rn_walktree_from(struct radix_node_head *h, void *a, void *m,
57                    walktree_f_t *f, void *w);
58static int rn_walktree(struct radix_node_head *, walktree_f_t *, void *);
59static struct radix_node
60         *rn_insert(void *, struct radix_node_head *, int *,
61                        struct radix_node [2]),
62         *rn_newpair(void *, int, struct radix_node[2]),
63         *rn_search(void *, struct radix_node *),
64         *rn_search_m(void *, struct radix_node *, void *);
65
66static int      max_keylen;
67static struct radix_mask *rn_mkfreelist;
68static struct radix_node_head *mask_rnhead;
69static char *addmask_key;
70static char normal_chars[] = {0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, -1};
71static char *rn_zeros, *rn_ones;
72
73#define rn_masktop (mask_rnhead->rnh_treetop)
74#undef Bcmp
75#define Bcmp(a, b, l) \
76        (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l))
77
78static int      rn_lexobetter(void *m_arg, void *n_arg);
79static struct radix_mask *
80                rn_new_radix_mask(struct radix_node *tt,
81                                       struct radix_mask *next);
82static int      rn_satisfies_leaf(char *trial, struct radix_node *leaf,
83                                       int skip);
84
85/*
86 * The data structure for the keys is a radix tree with one way
87 * branching removed.  The index rn_bit at an internal node n represents a bit
88 * position to be tested.  The tree is arranged so that all descendants
89 * of a node n have keys whose bits all agree up to position rn_bit - 1.
90 * (We say the index of n is rn_bit.)
91 *
92 * There is at least one descendant which has a one bit at position rn_bit,
93 * and at least one with a zero there.
94 *
95 * A route is determined by a pair of key and mask.  We require that the
96 * bit-wise logical and of the key and mask to be the key.
97 * We define the index of a route to associated with the mask to be
98 * the first bit number in the mask where 0 occurs (with bit number 0
99 * representing the highest order bit).
100 *
101 * We say a mask is normal if every bit is 0, past the index of the mask.
102 * If a node n has a descendant (k, m) with index(m) == index(n) == rn_bit,
103 * and m is a normal mask, then the route applies to every descendant of n.
104 * If the index(m) < rn_bit, this implies the trailing last few bits of k
105 * before bit b are all 0, (and hence consequently true of every descendant
106 * of n), so the route applies to all descendants of the node as well.
107 *
108 * Similar logic shows that a non-normal mask m such that
109 * index(m) <= index(n) could potentially apply to many children of n.
110 * Thus, for each non-host route, we attach its mask to a list at an internal
111 * node as high in the tree as we can go.
112 *
113 * The present version of the code makes use of normal routes in short-
114 * circuiting an explict mask and compare operation when testing whether
115 * a key satisfies a normal route, and also in remembering the unique leaf
116 * that governs a subtree.
117 */
118
119static struct radix_node *
120rn_search(void *v_arg, struct radix_node *head)
121{
122        register struct radix_node *x;
123        register caddr_t v;
124
125        for (x = head, v = v_arg; x->rn_bit >= 0;) {
126                if (x->rn_bmask & v[x->rn_offset])
127                        x = x->rn_right;
128                else
129                        x = x->rn_left;
130        }
131        return (x);
132}
133
134static struct radix_node *
135rn_search_m(void *v_arg, struct radix_node *head, void *m_arg)
136{
137        register struct radix_node *x;
138        register caddr_t v = v_arg, m = m_arg;
139
140        for (x = head; x->rn_bit >= 0;) {
141                if ((x->rn_bmask & m[x->rn_offset]) &&
142                    (x->rn_bmask & v[x->rn_offset]))
143                        x = x->rn_right;
144                else
145                        x = x->rn_left;
146        }
147        return x;
148}
149
150int
151rn_refines(void *m_arg, void *n_arg)
152{
153        register caddr_t m = m_arg, n = n_arg;
154        register caddr_t lim, lim2 = lim = n + *(u_char *)n;
155        int longer = (*(u_char *)n++) - (int)(*(u_char *)m++);
156        int masks_are_equal = 1;
157
158        if (longer > 0)
159                lim -= longer;
160        while (n < lim) {
161                if (*n & ~(*m))
162                        return 0;
163                if (*n++ != *m++)
164                        masks_are_equal = 0;
165        }
166        while (n < lim2)
167                if (*n++)
168                        return 0;
169        if (masks_are_equal && (longer < 0))
170                for (lim2 = m - longer; m < lim2; )
171                        if (*m++)
172                                return 1;
173        return (!masks_are_equal);
174}
175
176struct radix_node *
177rn_lookup(void *v_arg, void *m_arg, struct radix_node_head *head)
178{
179        register struct radix_node *x;
180        caddr_t netmask = 0;
181
182        if (m_arg) {
183                x = rn_addmask(m_arg, 1, head->rnh_treetop->rn_offset);
184                if (x == 0)
185                        return (0);
186                netmask = x->rn_key;
187        }
188        x = rn_match(v_arg, head);
189        if (x && netmask) {
190                while (x && x->rn_mask != netmask)
191                        x = x->rn_dupedkey;
192        }
193        return x;
194}
195
196static int
197rn_satisfies_leaf(char *trial, struct radix_node *leaf, int skip)
198{
199        register char *cp = trial, *cp2 = leaf->rn_key, *cp3 = leaf->rn_mask;
200        char *cplim;
201        int length = min(*(u_char *)cp, *(u_char *)cp2);
202
203        if (cp3 == 0)
204                cp3 = rn_ones;
205        else
206                length = min(length, *(u_char *)cp3);
207        cplim = cp + length; cp3 += skip; cp2 += skip;
208        for (cp += skip; cp < cplim; cp++, cp2++, cp3++)
209                if ((*cp ^ *cp2) & *cp3)
210                        return 0;
211        return 1;
212}
213
214struct radix_node *
215rn_match(void *v_arg, struct radix_node_head *head)
216{
217        caddr_t v = v_arg;
218        register struct radix_node *t = head->rnh_treetop, *x;
219        register caddr_t cp = v, cp2;
220        caddr_t cplim;
221        struct radix_node *saved_t, *top = t;
222        int off = t->rn_offset, vlen = *(u_char *)cp, matched_off;
223        register int test, b, rn_bit;
224
225        /*
226         * Open code rn_search(v, top) to avoid overhead of extra
227         * subroutine call.
228         */
229        for (; t->rn_bit >= 0; ) {
230                if (t->rn_bmask & cp[t->rn_offset])
231                        t = t->rn_right;
232                else
233                        t = t->rn_left;
234        }
235        /*
236         * See if we match exactly as a host destination
237         * or at least learn how many bits match, for normal mask finesse.
238         *
239         * It doesn't hurt us to limit how many bytes to check
240         * to the length of the mask, since if it matches we had a genuine
241         * match and the leaf we have is the most specific one anyway;
242         * if it didn't match with a shorter length it would fail
243         * with a long one.  This wins big for class B&C netmasks which
244         * are probably the most common case...
245         */
246        if (t->rn_mask)
247                vlen = *(u_char *)t->rn_mask;
248        cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
249        for (; cp < cplim; cp++, cp2++)
250                if (*cp != *cp2)
251                        goto on1;
252        /*
253         * This extra grot is in case we are explicitly asked
254         * to look up the default.  Ugh!
255         *
256         * Never return the root node itself, it seems to cause a
257         * lot of confusion.
258         */
259        if (t->rn_flags & RNF_ROOT)
260                t = t->rn_dupedkey;
261        return t;
262on1:
263        test = (*cp ^ *cp2) & 0xff; /* find first bit that differs */
264        for (b = 7; (test >>= 1) > 0;)
265                b--;
266        matched_off = cp - v;
267        b += matched_off << 3;
268        rn_bit = -1 - b;
269        /*
270         * If there is a host route in a duped-key chain, it will be first.
271         */
272        if ((saved_t = t)->rn_mask == 0)
273                t = t->rn_dupedkey;
274        for (; t; t = t->rn_dupedkey)
275                /*
276                 * Even if we don't match exactly as a host,
277                 * we may match if the leaf we wound up at is
278                 * a route to a net.
279                 */
280                if (t->rn_flags & RNF_NORMAL) {
281                        if (rn_bit <= t->rn_bit)
282                                return t;
283                } else if (rn_satisfies_leaf(v, t, matched_off))
284                                return t;
285        t = saved_t;
286        /* start searching up the tree */
287        do {
288                register struct radix_mask *m;
289                t = t->rn_parent;
290                m = t->rn_mklist;
291                if (m) {
292                        /*
293                         * If non-contiguous masks ever become important
294                         * we can restore the masking and open coding of
295                         * the search and satisfaction test and put the
296                         * calculation of "off" back before the "do".
297                         */
298                        do {
299                                if (m->rm_flags & RNF_NORMAL) {
300                                        if (rn_bit <= m->rm_bit)
301                                                return (m->rm_leaf);
302                                } else {
303                                        off = min(t->rn_offset, matched_off);
304                                        x = rn_search_m(v, t, m->rm_mask);
305                                        while (x && x->rn_mask != m->rm_mask)
306                                                x = x->rn_dupedkey;
307                                        if (x && rn_satisfies_leaf(v, x, off))
308                                                    return x;
309                                }
310                                m = m->rm_mklist;
311                        } while (m);
312                }
313        } while (t != top);
314        return 0;
315}
316
317#ifdef RN_DEBUG
318int     rn_nodenum;
319struct  radix_node *rn_clist;
320int     rn_saveinfo;
321int     rn_debug =  1;
322#endif
323
324static struct radix_node *
325rn_newpair(void *v, int b, struct radix_node nodes[2])
326{
327        register struct radix_node *tt = nodes, *t = tt + 1;
328        t->rn_bit = b;
329        t->rn_bmask = 0x80 >> (b & 7);
330        t->rn_left = tt;
331        t->rn_offset = b >> 3;
332        tt->rn_bit = -1;
333        tt->rn_key = (caddr_t)v;
334        tt->rn_parent = t;
335        tt->rn_flags = t->rn_flags = RNF_ACTIVE;
336#ifdef RN_DEBUG
337        tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
338        tt->rn_twin = t;
339        tt->rn_ybro = rn_clist;
340        rn_clist = tt;
341#endif
342        return t;
343}
344
345static struct radix_node *
346rn_insert(void *v_arg, struct radix_node_head *head, int *dupentry,
347    struct radix_node nodes[2])
348{
349        caddr_t v = v_arg;
350        struct radix_node *top = head->rnh_treetop;
351        int head_off = top->rn_offset, vlen = (int)*((u_char *)v);
352        register struct radix_node *t = rn_search(v_arg, top);
353        register caddr_t cp = v + head_off;
354        register int b;
355        struct radix_node *tt;
356        /*
357         * Find first bit at which v and t->rn_key differ
358         */
359    {
360        register caddr_t cp2 = t->rn_key + head_off;
361        register int cmp_res;
362        caddr_t cplim = v + vlen;
363
364        while (cp < cplim)
365                if (*cp2++ != *cp++)
366                        goto on1;
367        *dupentry = 1;
368        return t;
369on1:
370        *dupentry = 0;
371        cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
372        for (b = (cp - v) << 3; cmp_res; b--)
373                cmp_res >>= 1;
374    }
375    {
376        register struct radix_node *p, *x = top;
377        cp = v;
378        do {
379                p = x;
380                if (cp[x->rn_offset] & x->rn_bmask)
381                        x = x->rn_right;
382                else
383                        x = x->rn_left;
384        } while (b > (unsigned) x->rn_bit);
385                                /* x->rn_bit < b && x->rn_bit >= 0 */
386#ifdef RN_DEBUG
387        if (rn_debug)
388                log(LOG_DEBUG, "rn_insert: Going In:\n"), traverse(p);
389#endif
390        t = rn_newpair(v_arg, b, nodes);
391        tt = t->rn_left;
392        if ((cp[p->rn_offset] & p->rn_bmask) == 0)
393                p->rn_left = t;
394        else
395                p->rn_right = t;
396        x->rn_parent = t;
397        t->rn_parent = p; /* frees x, p as temp vars below */
398        if ((cp[t->rn_offset] & t->rn_bmask) == 0) {
399                t->rn_right = x;
400        } else {
401                t->rn_right = tt;
402                t->rn_left = x;
403        }
404#ifdef RN_DEBUG
405        if (rn_debug)
406                log(LOG_DEBUG, "rn_insert: Coming Out:\n"), traverse(p);
407#endif
408    }
409        return (tt);
410}
411
412struct radix_node *
413rn_addmask(void *n_arg, int search, int skip)
414{
415        caddr_t netmask = (caddr_t)n_arg;
416        register struct radix_node *x;
417        register caddr_t cp, cplim;
418        register int b = 0, mlen, j;
419        int maskduplicated, m0, isnormal;
420        struct radix_node *saved_x;
421        static int last_zeroed = 0;
422
423        if ((mlen = *(u_char *)netmask) > max_keylen)
424                mlen = max_keylen;
425        if (skip == 0)
426                skip = 1;
427        if (mlen <= skip)
428                return (mask_rnhead->rnh_nodes);
429        if (skip > 1)
430                Bcopy(rn_ones + 1, addmask_key + 1, skip - 1);
431        if ((m0 = mlen) > skip)
432                Bcopy(netmask + skip, addmask_key + skip, mlen - skip);
433        /*
434         * Trim trailing zeroes.
435         */
436        for (cp = addmask_key + mlen; (cp > addmask_key) && cp[-1] == 0;)
437                cp--;
438        mlen = cp - addmask_key;
439        if (mlen <= skip) {
440                if (m0 >= last_zeroed)
441                        last_zeroed = mlen;
442                return (mask_rnhead->rnh_nodes);
443        }
444        if (m0 < last_zeroed)
445                Bzero(addmask_key + m0, last_zeroed - m0);
446        *addmask_key = last_zeroed = mlen;
447        x = rn_search(addmask_key, rn_masktop);
448        if (Bcmp(addmask_key, x->rn_key, mlen) != 0)
449                x = 0;
450        if (x || search)
451                return (x);
452        R_Malloc(x, struct radix_node *, max_keylen + 2 * sizeof (*x));
453        if ((saved_x = x) == 0)
454                return (0);
455        Bzero(x, max_keylen + 2 * sizeof (*x));
456        netmask = cp = (caddr_t)(x + 2);
457        Bcopy(addmask_key, cp, mlen);
458        x = rn_insert(cp, mask_rnhead, &maskduplicated, x);
459        if (maskduplicated) {
460                log(LOG_ERR, "rn_addmask: mask impossibly already in tree");
461                Free(saved_x);
462                return (x);
463        }
464        /*
465         * Calculate index of mask, and check for normalcy.
466         */
467        cplim = netmask + mlen; isnormal = 1;
468        for (cp = netmask + skip; (cp < cplim) && *(u_char *)cp == 0xff;)
469                cp++;
470        if (cp != cplim) {
471                for (j = 0x80; (j & *cp) != 0; j >>= 1)
472                        b++;
473                if (*cp != normal_chars[b] || cp != (cplim - 1))
474                        isnormal = 0;
475        }
476        b += (cp - netmask) << 3;
477        x->rn_bit = -1 - b;
478        if (isnormal)
479                x->rn_flags |= RNF_NORMAL;
480        return (x);
481}
482
483static int      /* XXX: arbitrary ordering for non-contiguous masks */
484rn_lexobetter(void *m_arg, void *n_arg)
485{
486        register u_char *mp = m_arg, *np = n_arg, *lim;
487
488        if (*mp > *np)
489                return 1;  /* not really, but need to check longer one first */
490        if (*mp == *np)
491                for (lim = mp + *mp; mp < lim;)
492                        if (*mp++ > *np++)
493                                return 1;
494        return 0;
495}
496
497static struct radix_mask *
498rn_new_radix_mask(struct radix_node *tt, struct radix_mask *next)
499{
500        register struct radix_mask *m;
501
502        MKGet(m);
503        if (m == 0) {
504                log(LOG_ERR, "Mask for route not entered\n");
505                return (0);
506        }
507        Bzero(m, sizeof *m);
508        m->rm_bit = tt->rn_bit;
509        m->rm_flags = tt->rn_flags;
510        if (tt->rn_flags & RNF_NORMAL)
511                m->rm_leaf = tt;
512        else
513                m->rm_mask = tt->rn_mask;
514        m->rm_mklist = next;
515        tt->rn_mklist = m;
516        return m;
517}
518
519struct radix_node *
520rn_addroute(void *v_arg, void *n_arg, struct radix_node_head *head,
521     struct radix_node treenodes[2])
522{
523        caddr_t v = (caddr_t)v_arg, netmask = (caddr_t)n_arg;
524        register struct radix_node *t, *x = 0, *tt;
525        struct radix_node *saved_tt, *top = head->rnh_treetop;
526        short b = 0, b_leaf = 0;
527        int keyduplicated;
528        caddr_t mmask;
529        struct radix_mask *m, **mp;
530
531        /*
532         * In dealing with non-contiguous masks, there may be
533         * many different routes which have the same mask.
534         * We will find it useful to have a unique pointer to
535         * the mask to speed avoiding duplicate references at
536         * nodes and possibly save time in calculating indices.
537         */
538        if (netmask)  {
539                if ((x = rn_addmask(netmask, 0, top->rn_offset)) == 0)
540                        return (0);
541                b_leaf = x->rn_bit;
542                b = -1 - x->rn_bit;
543                netmask = x->rn_key;
544        }
545        /*
546         * Deal with duplicated keys: attach node to previous instance
547         */
548        saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
549        if (keyduplicated) {
550                for (t = tt; tt; t = tt, tt = tt->rn_dupedkey) {
551                        if (tt->rn_mask == netmask)
552                                return (0);
553                        if (netmask == 0 ||
554                            (tt->rn_mask &&
555                             ((b_leaf < tt->rn_bit) /* index(netmask) > node */
556                              || rn_refines(netmask, tt->rn_mask)
557                              || rn_lexobetter(netmask, tt->rn_mask))))
558                                break;
559                }
560                /*
561                 * If the mask is not duplicated, we wouldn't
562                 * find it among possible duplicate key entries
563                 * anyway, so the above test doesn't hurt.
564                 *
565                 * We sort the masks for a duplicated key the same way as
566                 * in a masklist -- most specific to least specific.
567                 * This may require the unfortunate nuisance of relocating
568                 * the head of the list.
569                 *
570                 * We also reverse, or doubly link the list through the
571                 * parent pointer.
572                 */
573                if (tt == saved_tt) {
574                        struct  radix_node *xx = x;
575                        /* link in at head of list */
576                        (tt = treenodes)->rn_dupedkey = t;
577                        tt->rn_flags = t->rn_flags;
578                        tt->rn_parent = x = t->rn_parent;
579                        t->rn_parent = tt;                              /* parent */
580                        if (x->rn_left == t)
581                                x->rn_left = tt;
582                        else
583                                x->rn_right = tt;
584                        saved_tt = tt; x = xx;
585                } else {
586                        (tt = treenodes)->rn_dupedkey = t->rn_dupedkey;
587                        t->rn_dupedkey = tt;
588                        tt->rn_parent = t;                              /* parent */
589                        if (tt->rn_dupedkey)                    /* parent */
590                                tt->rn_dupedkey->rn_parent = tt;        /* parent */
591                }
592#ifdef RN_DEBUG
593                t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
594                tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
595#endif
596                tt->rn_key = (caddr_t) v;
597                tt->rn_bit = -1;
598                tt->rn_flags = RNF_ACTIVE;
599        }
600        /*
601         * Put mask in tree.
602         */
603        if (netmask) {
604                tt->rn_mask = netmask;
605                tt->rn_bit = x->rn_bit;
606                tt->rn_flags |= x->rn_flags & RNF_NORMAL;
607        }
608        t = saved_tt->rn_parent;
609        if (keyduplicated)
610                goto on2;
611        b_leaf = -1 - t->rn_bit;
612        if (t->rn_right == saved_tt)
613                x = t->rn_left;
614        else
615                x = t->rn_right;
616        /* Promote general routes from below */
617        if (x->rn_bit < 0) {
618            for (mp = &t->rn_mklist; x; x = x->rn_dupedkey)
619                if (x->rn_mask && (x->rn_bit >= b_leaf) && x->rn_mklist == 0) {
620                        *mp = m = rn_new_radix_mask(x, 0);
621                        if (m)
622                                mp = &m->rm_mklist;
623                }
624        } else if (x->rn_mklist) {
625                /*
626                 * Skip over masks whose index is > that of new node
627                 */
628                for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
629                        if (m->rm_bit >= b_leaf)
630                                break;
631                t->rn_mklist = m; *mp = 0;
632        }
633on2:
634        /* Add new route to highest possible ancestor's list */
635        if ((netmask == 0) || (b > t->rn_bit ))
636                return tt; /* can't lift at all */
637        b_leaf = tt->rn_bit;
638        do {
639                x = t;
640                t = t->rn_parent;
641        } while (b <= t->rn_bit && x != top);
642        /*
643         * Search through routes associated with node to
644         * insert new route according to index.
645         * Need same criteria as when sorting dupedkeys to avoid
646         * double loop on deletion.
647         */
648        for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist) {
649                if (m->rm_bit < b_leaf)
650                        continue;
651                if (m->rm_bit > b_leaf)
652                        break;
653                if (m->rm_flags & RNF_NORMAL) {
654                        mmask = m->rm_leaf->rn_mask;
655                        if (tt->rn_flags & RNF_NORMAL) {
656                                log(LOG_ERR,
657                                "Non-unique normal route, mask not entered\n");
658                                return tt;
659                        }
660                } else
661                        mmask = m->rm_mask;
662                if (mmask == netmask) {
663                        m->rm_refs++;
664                        tt->rn_mklist = m;
665                        return tt;
666                }
667                if (rn_refines(netmask, mmask)
668                    || rn_lexobetter(netmask, mmask))
669                        break;
670        }
671        *mp = rn_new_radix_mask(tt, *mp);
672        return tt;
673}
674
675struct radix_node *
676rn_delete(void *v_arg, void *netmask_arg, struct radix_node_head *head)
677{
678        register struct radix_node *t, *p, *x, *tt;
679        struct radix_mask *m, *saved_m, **mp;
680        struct radix_node *dupedkey, *saved_tt, *top;
681        caddr_t v, netmask;
682        int b, head_off, vlen;
683
684        v = v_arg;
685        netmask = netmask_arg;
686        x = head->rnh_treetop;
687        tt = rn_search(v, x);
688        head_off = x->rn_offset;
689        vlen =  *(u_char *)v;
690        saved_tt = tt;
691        top = x;
692        if (tt == 0 ||
693            Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
694                return (0);
695        /*
696         * Delete our route from mask lists.
697         */
698        if (netmask) {
699                if ((x = rn_addmask(netmask, 1, head_off)) == 0)
700                        return (0);
701                netmask = x->rn_key;
702                while (tt->rn_mask != netmask)
703                        if ((tt = tt->rn_dupedkey) == 0)
704                                return (0);
705        }
706        if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
707                goto on1;
708        if (tt->rn_flags & RNF_NORMAL) {
709                if (m->rm_leaf != tt || m->rm_refs > 0) {
710                        log(LOG_ERR, "rn_delete: inconsistent annotation\n");
711                        return 0;  /* dangling ref could cause disaster */
712                }
713        } else {
714                if (m->rm_mask != tt->rn_mask) {
715                        log(LOG_ERR, "rn_delete: inconsistent annotation\n");
716                        goto on1;
717                }
718                if (--m->rm_refs >= 0)
719                        goto on1;
720        }
721        b = -1 - tt->rn_bit;
722        t = saved_tt->rn_parent;
723        if (b > t->rn_bit)
724                goto on1; /* Wasn't lifted at all */
725        do {
726                x = t;
727                t = t->rn_parent;
728        } while (b <= t->rn_bit && x != top);
729        for (mp = &x->rn_mklist; (m = *mp); mp = &m->rm_mklist)
730                if (m == saved_m) {
731                        *mp = m->rm_mklist;
732                        MKFree(m);
733                        break;
734                }
735        if (m == 0) {
736                log(LOG_ERR, "rn_delete: couldn't find our annotation\n");
737                if (tt->rn_flags & RNF_NORMAL)
738                        return (0); /* Dangling ref to us */
739        }
740on1:
741        /*
742         * Eliminate us from tree
743         */
744        if (tt->rn_flags & RNF_ROOT)
745                return (0);
746#ifdef RN_DEBUG
747        /* Get us out of the creation list */
748        for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}
749        if (t) t->rn_ybro = tt->rn_ybro;
750#endif
751        t = tt->rn_parent;
752        dupedkey = saved_tt->rn_dupedkey;
753        if (dupedkey) {
754                /*
755                 * Here, tt is the deletion target and
756                 * saved_tt is the head of the dupekey chain.
757                 */
758                if (tt == saved_tt) {
759                        /* remove from head of chain */
760                        x = dupedkey; x->rn_parent = t;
761                        if (t->rn_left == tt)
762                                t->rn_left = x;
763                        else
764                                t->rn_right = x;
765                } else {
766                        /* find node in front of tt on the chain */
767                        for (x = p = saved_tt; p && p->rn_dupedkey != tt;)
768                                p = p->rn_dupedkey;
769                        if (p) {
770                                p->rn_dupedkey = tt->rn_dupedkey;
771                                if (tt->rn_dupedkey)               /* parent */
772                                        tt->rn_dupedkey->rn_parent = p;
773                                                                /* parent */
774                        } else log(LOG_ERR, "rn_delete: couldn't find us\n");
775                }
776                t = tt + 1;
777                if  (t->rn_flags & RNF_ACTIVE) {
778#ifndef RN_DEBUG
779                        *++x = *t;
780                        p = t->rn_parent;
781#else
782                        b = t->rn_info;
783                        *++x = *t;
784                        t->rn_info = b;
785                        p = t->rn_parent;
786#endif
787                        if (p->rn_left == t)
788                                p->rn_left = x;
789                        else
790                                p->rn_right = x;
791                        x->rn_left->rn_parent = x;
792                        x->rn_right->rn_parent = x;
793                }
794                goto out;
795        }
796        if (t->rn_left == tt)
797                x = t->rn_right;
798        else
799                x = t->rn_left;
800        p = t->rn_parent;
801        if (p->rn_right == t)
802                p->rn_right = x;
803        else
804                p->rn_left = x;
805        x->rn_parent = p;
806        /*
807         * Demote routes attached to us.
808         */
809        if (t->rn_mklist) {
810                if (x->rn_bit >= 0) {
811                        for (mp = &x->rn_mklist; (m = *mp);)
812                                mp = &m->rm_mklist;
813                        *mp = t->rn_mklist;
814                } else {
815                        /* If there are any key,mask pairs in a sibling
816                           duped-key chain, some subset will appear sorted
817                           in the same order attached to our mklist */
818                        for (m = t->rn_mklist; m && x; x = x->rn_dupedkey)
819                                if (m == x->rn_mklist) {
820                                        struct radix_mask *mm = m->rm_mklist;
821                                        x->rn_mklist = 0;
822                                        if (--(m->rm_refs) < 0)
823                                                MKFree(m);
824                                        m = mm;
825                                }
826                        if (m)
827                                log(LOG_ERR,
828                                    "rn_delete: Orphaned Mask %p at %p\n",
829                                    (void *)m, (void *)x);
830                }
831        }
832        /*
833         * We may be holding an active internal node in the tree.
834         */
835        x = tt + 1;
836        if (t != x) {
837#ifndef RN_DEBUG
838                *t = *x;
839#else
840                b = t->rn_info;
841                *t = *x;
842                t->rn_info = b;
843#endif
844                t->rn_left->rn_parent = t;
845                t->rn_right->rn_parent = t;
846                p = x->rn_parent;
847                if (p->rn_left == x)
848                        p->rn_left = t;
849                else
850                        p->rn_right = t;
851        }
852out:
853        tt->rn_flags &= ~RNF_ACTIVE;
854        tt[1].rn_flags &= ~RNF_ACTIVE;
855        return (tt);
856}
857
858/*
859 * This is the same as rn_walktree() except for the parameters and the
860 * exit.
861 */
862static int
863rn_walktree_from(struct radix_node_head *h, void *a, void *m,
864     walktree_f_t *f, void *w)
865{
866        int error;
867        struct radix_node *base, *next;
868        u_char *xa = (u_char *)a;
869        u_char *xm = (u_char *)m;
870        register struct radix_node *rn, *last = 0 /* shut up gcc */;
871        int stopping = 0;
872        int lastb;
873
874        /*
875         * rn_search_m is sort-of-open-coded here.
876         */
877        /* printf("about to search\n"); */
878        for (rn = h->rnh_treetop; rn->rn_bit >= 0; ) {
879                last = rn;
880                /* printf("rn_bit %d, rn_bmask %x, xm[rn_offset] %x\n",
881                       rn->rn_bit, rn->rn_bmask, xm[rn->rn_offset]); */
882                if (!(rn->rn_bmask & xm[rn->rn_offset])) {
883                        break;
884                }
885                if (rn->rn_bmask & xa[rn->rn_offset]) {
886                        rn = rn->rn_right;
887                } else {
888                        rn = rn->rn_left;
889                }
890        }
891        /* printf("done searching\n"); */
892
893        /*
894         * Two cases: either we stepped off the end of our mask,
895         * in which case last == rn, or we reached a leaf, in which
896         * case we want to start from the last node we looked at.
897         * Either way, last is the node we want to start from.
898         */
899        rn = last;
900        lastb = rn->rn_bit;
901
902        /* printf("rn %p, lastb %d\n", rn, lastb);*/
903
904        /*
905         * This gets complicated because we may delete the node
906         * while applying the function f to it, so we need to calculate
907         * the successor node in advance.
908         */
909        while (rn->rn_bit >= 0)
910                rn = rn->rn_left;
911
912        while (!stopping) {
913                /* printf("node %p (%d)\n", rn, rn->rn_bit); */
914                base = rn;
915                /* If at right child go back up, otherwise, go right */
916                while (rn->rn_parent->rn_right == rn
917                       && !(rn->rn_flags & RNF_ROOT)) {
918                        rn = rn->rn_parent;
919
920                        /* if went up beyond last, stop */
921                        if (rn->rn_bit < lastb) {
922                                stopping = 1;
923                                /* printf("up too far\n"); */
924                        }
925                }
926
927                /* Find the next *leaf* since next node might vanish, too */
928                for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
929                        rn = rn->rn_left;
930                next = rn;
931                /* Process leaves */
932                while ((rn = base) != 0) {
933                        base = rn->rn_dupedkey;
934                        /* printf("leaf %p\n", rn); */
935                        if (!(rn->rn_flags & RNF_ROOT)
936                            && (error = (*f)(rn, w)))
937                                return (error);
938                }
939                rn = next;
940
941                if (rn->rn_flags & RNF_ROOT) {
942                        /* printf("root, stopping"); */
943                        stopping = 1;
944                }
945
946        }
947        return 0;
948}
949
950static int
951rn_walktree(struct radix_node_head *h, walktree_f_t *f, void *w)
952{
953        int error;
954        struct radix_node *base, *next;
955        register struct radix_node *rn = h->rnh_treetop;
956        /*
957         * This gets complicated because we may delete the node
958         * while applying the function f to it, so we need to calculate
959         * the successor node in advance.
960         */
961        /* First time through node, go left */
962        while (rn->rn_bit >= 0)
963                rn = rn->rn_left;
964        for (;;) {
965                base = rn;
966                /* If at right child go back up, otherwise, go right */
967                while (rn->rn_parent->rn_right == rn
968                       && (rn->rn_flags & RNF_ROOT) == 0)
969                        rn = rn->rn_parent;
970                /* Find the next *leaf* since next node might vanish, too */
971                for (rn = rn->rn_parent->rn_right; rn->rn_bit >= 0;)
972                        rn = rn->rn_left;
973                next = rn;
974                /* Process leaves */
975                while ((rn = base)) {
976                        base = rn->rn_dupedkey;
977                        if (!(rn->rn_flags & RNF_ROOT)
978                            && (error = (*f)(rn, w)))
979                                return (error);
980                }
981                rn = next;
982                if (rn->rn_flags & RNF_ROOT)
983                        return (0);
984        }
985        /* NOTREACHED */
986}
987
988int
989rn_inithead(void **head, int off)
990{
991        register struct radix_node_head *rnh;
992        register struct radix_node *t, *tt, *ttt;
993        if (*head)
994                return (1);
995        R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh));
996        if (rnh == 0)
997                return (0);
998        Bzero(rnh, sizeof (*rnh));
999        *head = rnh;
1000        t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
1001        ttt = rnh->rnh_nodes + 2;
1002        t->rn_right = ttt;
1003        t->rn_parent = t;
1004        tt = t->rn_left;
1005        tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
1006        tt->rn_bit = -1 - off;
1007        *ttt = *tt;
1008        ttt->rn_key = rn_ones;
1009        rnh->rnh_addaddr = rn_addroute;
1010        rnh->rnh_deladdr = rn_delete;
1011        rnh->rnh_matchaddr = rn_match;
1012        rnh->rnh_lookup = rn_lookup;
1013        rnh->rnh_walktree = rn_walktree;
1014        rnh->rnh_walktree_from = rn_walktree_from;
1015        rnh->rnh_treetop = t;
1016        return (1);
1017}
1018
1019void
1020rn_init(void)
1021{
1022        char *cp, *cplim;
1023#ifdef _KERNEL
1024        struct domain *dom;
1025
1026        for (dom = domains; dom; dom = dom->dom_next)
1027                if (dom->dom_maxrtkey > max_keylen)
1028                        max_keylen = dom->dom_maxrtkey;
1029#endif
1030        if (max_keylen == 0) {
1031                log(LOG_ERR,
1032                    "rn_init: radix functions require max_keylen be set\n");
1033                return;
1034        }
1035        R_Malloc(rn_zeros, char *, 3 * max_keylen);
1036        if (rn_zeros == NULL)
1037                panic("rn_init");
1038        Bzero(rn_zeros, 3 * max_keylen);
1039        rn_ones = cp = rn_zeros + max_keylen;
1040        addmask_key = cplim = rn_ones + max_keylen;
1041        while (cp < cplim)
1042                *cp++ = -1;
1043        if (rn_inithead((void **)(void*)&mask_rnhead, 0) == 0)
1044                panic("rn_init 2");
1045}
Note: See TracBrowser for help on using the repository browser.