📄 radix.c
字号:
/* $Id: radix.c,v 1.2 1996/01/16 14:21:56 chris Exp $ *//* * Copyright (c) 1988, 1989 Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)radix.c 7.9 (Berkeley) 2/4/91 *//* * Routines to build and maintain radix trees for routing lookups. */#ifndef RNF_NORMAL#include "param.h"#include "radix.h"#include "malloc.h"#define M_DONTWAIT M_NOWAIT#endifstruct radix_node_head *mask_rnhead;#define rn_maskhead mask_rnhead->rnh_treetopstruct radix_mask *rn_mkfreelist;struct radix_node_head *radix_node_head;#undef Bcmp#define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l))/* * The data structure for the keys is a radix tree with one way * branching removed. The index rn_b at an internal node n represents a bit * position to be tested. The tree is arranged so that all descendants * of a node n have keys whose bits all agree up to position rn_b - 1. * (We say the index of n is rn_b.) * * There is at least one descendant which has a one bit at position rn_b, * and at least one with a zero there. * * A route is determined by a pair of key and mask. We require that the * bit-wise logical and of the key and mask to be the key. * We define the index of a route to associated with the mask to be * the first bit number in the mask where 0 occurs (with bit number 0 * representing the highest order bit). * * We say a mask is normal if every bit is 0, past the index of the mask. * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b, * and m is a normal mask, then the route applies to every descendant of n. * If the index(m) < rn_b, this implies the trailing last few bits of k * before bit b are all 0, (and hence consequently true of every descendant * of n), so the route applies to all descendants of the node as well. * * The present version of the code makes no use of normal routes, * but similar logic shows that a non-normal mask m such that * index(m) <= index(n) could potentially apply to many children of n. * Thus, for each non-host route, we attach its mask to a list at an internal * node as high in the tree as we can go. */struct radix_node *rn_search(v, head) struct radix_node *head; register caddr_t v;{ register struct radix_node *x; for (x = head; x->rn_b >= 0;) { if (x->rn_bmask & v[x->rn_off]) x = x->rn_r; else x = x->rn_l; } return x;};struct radix_node *rn_search_m(v, head, m) struct radix_node *head; register caddr_t v, m;{ register struct radix_node *x; for (x = head; x->rn_b >= 0;) { if ((x->rn_bmask & m[x->rn_off]) && (x->rn_bmask & v[x->rn_off])) x = x->rn_r; else x = x->rn_l; } return x;};static int gotOddMasks;static char maskedKey[MAXKEYLEN];struct radix_node *rn_match(v, head) struct radix_node *head; caddr_t v;{ register struct radix_node *t = head, *x; register caddr_t cp = v, cp2, cp3; caddr_t cplim, mstart; struct radix_node *saved_t; int off = t->rn_off, vlen = *(u_char *)cp, matched_off; /* * Open code rn_search(v, head) to avoid overhead of extra * subroutine call. */ for (; t->rn_b >= 0; ) { if (t->rn_bmask & cp[t->rn_off]) t = t->rn_r; else t = t->rn_l; } /* * See if we match exactly as a host destination */ cp += off; cp2 = t->rn_key + off; cplim = v + vlen; for (; cp < cplim; cp++, cp2++) if (*cp != *cp2) goto on1; /* * This extra grot is in case we are explicitly asked * to look up the default. Ugh! */ if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey) t = t->rn_dupedkey; return t;on1: matched_off = cp - v; saved_t = t; do { if (t->rn_mask) { /* * Even if we don't match exactly as a hosts; * we may match if the leaf we wound up at is * a route to a net. */ cp3 = matched_off + t->rn_mask; cp2 = matched_off + t->rn_key; for (; cp < cplim; cp++) if ((*cp2++ ^ *cp) & *cp3++) break; if (cp == cplim) return t; cp = matched_off + v; } } while (t = t->rn_dupedkey); t = saved_t; /* start searching up the tree */ do { register struct radix_mask *m; t = t->rn_p; if (m = t->rn_mklist) { /* * After doing measurements here, it may * turn out to be faster to open code * rn_search_m here instead of always * copying and masking. */ off = min(t->rn_off, matched_off); mstart = maskedKey + off; do { cp2 = mstart; cp3 = m->rm_mask + off; for (cp = v + off; cp < cplim;) *cp2++ = *cp++ & *cp3++; x = rn_search(maskedKey, t); while (x && x->rn_mask != m->rm_mask) x = x->rn_dupedkey; if (x && (Bcmp(mstart, x->rn_key + off, vlen - off) == 0)) return x; } while (m = m->rm_mklist); } } while (t != head); return 0;}; #ifdef RN_DEBUGint rn_nodenum;struct radix_node *rn_clist;int rn_saveinfo;#endifstruct radix_node *rn_newpair(v, b, nodes) caddr_t v; struct radix_node nodes[2];{ register struct radix_node *tt = nodes, *t = tt + 1; t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7); t->rn_l = tt; t->rn_off = b >> 3; tt->rn_b = -1; tt->rn_key = v; tt->rn_p = t; tt->rn_flags = t->rn_flags = RNF_ACTIVE;#ifdef RN_DEBUG tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++; tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;#endif return t;}#ifdef RN_DEBUGint rn_debug = 1;#endifstruct radix_node *rn_insert(v, head, dupentry, nodes) caddr_t v; struct radix_node *head; int *dupentry; struct radix_node nodes[2];{ int head_off = head->rn_off, vlen = (int)*((u_char *)v); register struct radix_node *t = rn_search(v, head); register caddr_t cp = v + head_off; register int b; struct radix_node *tt; /* *find first bit at which v and t->rn_key differ */ { register caddr_t cp2 = t->rn_key + head_off; register int cmp_res; caddr_t cplim = v + vlen; while (cp < cplim) if (*cp2++ != *cp++) goto on1; *dupentry = 1; return t;on1: *dupentry = 0; cmp_res = (cp[-1] ^ cp2[-1]) & 0xff; for (b = (cp - v) << 3; cmp_res; b--) cmp_res >>= 1; } { register struct radix_node *p, *x = head; cp = v; do { p = x; if (cp[x->rn_off] & x->rn_bmask) x = x->rn_r; else x = x->rn_l; } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */#ifdef RN_DEBUG if (rn_debug) printf("Going In:\n"), traverse(p);#endif t = rn_newpair(v, b, nodes); tt = t->rn_l; if ((cp[p->rn_off] & p->rn_bmask) == 0) p->rn_l = t; else p->rn_r = t; x->rn_p = t; t->rn_p = p; /* frees x, p as temp vars below */ if ((cp[t->rn_off] & t->rn_bmask) == 0) { t->rn_r = x; } else { t->rn_r = tt; t->rn_l = x; }#ifdef RN_DEBUG if (rn_debug) printf("Coming out:\n"), traverse(p);#endif } return (tt);}struct radix_node *rn_addmask(netmask, search, skip)caddr_t netmask;{ register struct radix_node *x; register caddr_t cp, cplim; register int b, mlen, j; int maskduplicated; mlen = *(u_char *)netmask; if (search) { x = rn_search(netmask, rn_maskhead); mlen = *(u_char *)netmask; if (Bcmp(netmask, x->rn_key, mlen) == 0) return (x); } R_Malloc(x, struct radix_node *, MAXKEYLEN + 2 * sizeof (*x)); if (x == 0) return (0); Bzero(x, MAXKEYLEN + 2 * sizeof (*x)); cp = (caddr_t)(x + 2); Bcopy(netmask, cp, mlen); netmask = cp; x = rn_insert(netmask, rn_maskhead, &maskduplicated, x); /* * Calculate index of mask. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -