Annotation of XNU/bsd/net/radix.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.