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

4.104.115
Last change on this file since b25b88e7 was b25b88e7, checked in by Ralf Corsepius <ralf.corsepius@…>, on 03/28/10 at 05:50:29

Add HAVE_CONFIG_H support to let files receive configure defines.

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