|
|
1.1 root 1: /*
2: * Copyright (c) 1988, 1989 Regents of the University of California.
3: * 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: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)radix.c 7.9 (Berkeley) 2/4/91
34: */
35:
36: /*
37: * Routines to build and maintain radix trees for routing lookups.
38: */
39: #ifndef RNF_NORMAL
40: #include "param.h"
41: #include "radix.h"
42: #include "malloc.h"
43: #define M_DONTWAIT M_NOWAIT
44: #endif
45: struct radix_node_head *mask_rnhead;
46: #define rn_maskhead mask_rnhead->rnh_treetop
47: struct radix_mask *rn_mkfreelist;
48: struct radix_node_head *radix_node_head;
49: #undef Bcmp
50: #define Bcmp(a, b, l) (l == 0 ? 0 : bcmp((caddr_t)(a), (caddr_t)(b), (u_long)l))
51: /*
52: * The data structure for the keys is a radix tree with one way
53: * branching removed. The index rn_b at an internal node n represents a bit
54: * position to be tested. The tree is arranged so that all descendants
55: * of a node n have keys whose bits all agree up to position rn_b - 1.
56: * (We say the index of n is rn_b.)
57: *
58: * There is at least one descendant which has a one bit at position rn_b,
59: * and at least one with a zero there.
60: *
61: * A route is determined by a pair of key and mask. We require that the
62: * bit-wise logical and of the key and mask to be the key.
63: * We define the index of a route to associated with the mask to be
64: * the first bit number in the mask where 0 occurs (with bit number 0
65: * representing the highest order bit).
66: *
67: * We say a mask is normal if every bit is 0, past the index of the mask.
68: * If a node n has a descendant (k, m) with index(m) == index(n) == rn_b,
69: * and m is a normal mask, then the route applies to every descendant of n.
70: * If the index(m) < rn_b, this implies the trailing last few bits of k
71: * before bit b are all 0, (and hence consequently true of every descendant
72: * of n), so the route applies to all descendants of the node as well.
73: *
74: * The present version of the code makes no use of normal routes,
75: * but similar logic shows that a non-normal mask m such that
76: * index(m) <= index(n) could potentially apply to many children of n.
77: * Thus, for each non-host route, we attach its mask to a list at an internal
78: * node as high in the tree as we can go.
79: */
80:
81: struct radix_node *
82: rn_search(v, head)
83: struct radix_node *head;
84: register caddr_t v;
85: {
86: register struct radix_node *x;
87:
88: for (x = head; x->rn_b >= 0;) {
89: if (x->rn_bmask & v[x->rn_off])
90: x = x->rn_r;
91: else
92: x = x->rn_l;
93: }
94: return x;
95: };
96:
97: struct radix_node *
98: rn_search_m(v, head, m)
99: struct radix_node *head;
100: register caddr_t v, m;
101: {
102: register struct radix_node *x;
103:
104: for (x = head; x->rn_b >= 0;) {
105: if ((x->rn_bmask & m[x->rn_off]) &&
106: (x->rn_bmask & v[x->rn_off]))
107: x = x->rn_r;
108: else
109: x = x->rn_l;
110: }
111: return x;
112: };
113:
114:
115: static int gotOddMasks;
116: static char maskedKey[MAXKEYLEN];
117:
118: struct radix_node *
119: rn_match(v, head)
120: struct radix_node *head;
121: caddr_t v;
122: {
123: register struct radix_node *t = head, *x;
124: register caddr_t cp = v, cp2, cp3;
125: caddr_t cplim, mstart;
126: struct radix_node *saved_t;
127: int off = t->rn_off, vlen = *(u_char *)cp, matched_off;
128:
129: /*
130: * Open code rn_search(v, head) to avoid overhead of extra
131: * subroutine call.
132: */
133: for (; t->rn_b >= 0; ) {
134: if (t->rn_bmask & cp[t->rn_off])
135: t = t->rn_r;
136: else
137: t = t->rn_l;
138: }
139: /*
140: * See if we match exactly as a host destination
141: */
142: cp += off; cp2 = t->rn_key + off; cplim = v + vlen;
143: for (; cp < cplim; cp++, cp2++)
144: if (*cp != *cp2)
145: goto on1;
146: /*
147: * This extra grot is in case we are explicitly asked
148: * to look up the default. Ugh!
149: */
150: if ((t->rn_flags & RNF_ROOT) && t->rn_dupedkey)
151: t = t->rn_dupedkey;
152: return t;
153: on1:
154: matched_off = cp - v;
155: saved_t = t;
156: do {
157: if (t->rn_mask) {
158: /*
159: * Even if we don't match exactly as a hosts;
160: * we may match if the leaf we wound up at is
161: * a route to a net.
162: */
163: cp3 = matched_off + t->rn_mask;
164: cp2 = matched_off + t->rn_key;
165: for (; cp < cplim; cp++)
166: if ((*cp2++ ^ *cp) & *cp3++)
167: break;
168: if (cp == cplim)
169: return t;
170: cp = matched_off + v;
171: }
172: } while (t = t->rn_dupedkey);
173: t = saved_t;
174: /* start searching up the tree */
175: do {
176: register struct radix_mask *m;
177: t = t->rn_p;
178: if (m = t->rn_mklist) {
179: /*
180: * After doing measurements here, it may
181: * turn out to be faster to open code
182: * rn_search_m here instead of always
183: * copying and masking.
184: */
185: off = min(t->rn_off, matched_off);
186: mstart = maskedKey + off;
187: do {
188: cp2 = mstart;
189: cp3 = m->rm_mask + off;
190: for (cp = v + off; cp < cplim;)
191: *cp2++ = *cp++ & *cp3++;
192: x = rn_search(maskedKey, t);
193: while (x && x->rn_mask != m->rm_mask)
194: x = x->rn_dupedkey;
195: if (x &&
196: (Bcmp(mstart, x->rn_key + off,
197: vlen - off) == 0))
198: return x;
199: } while (m = m->rm_mklist);
200: }
201: } while (t != head);
202: return 0;
203: };
204:
205: #ifdef RN_DEBUG
206: int rn_nodenum;
207: struct radix_node *rn_clist;
208: int rn_saveinfo;
209: #endif
210:
211: struct radix_node *
212: rn_newpair(v, b, nodes)
213: caddr_t v;
214: struct radix_node nodes[2];
215: {
216: register struct radix_node *tt = nodes, *t = tt + 1;
217: t->rn_b = b; t->rn_bmask = 0x80 >> (b & 7);
218: t->rn_l = tt; t->rn_off = b >> 3;
219: tt->rn_b = -1; tt->rn_key = v; tt->rn_p = t;
220: tt->rn_flags = t->rn_flags = RNF_ACTIVE;
221: #ifdef RN_DEBUG
222: tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
223: tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
224: #endif
225: return t;
226: }
227:
228: int rn_debug = 1;
229: struct radix_node *
230: rn_insert(v, head, dupentry, nodes)
231: caddr_t v;
232: struct radix_node *head;
233: int *dupentry;
234: struct radix_node nodes[2];
235: {
236: int head_off = head->rn_off, vlen = (int)*((u_char *)v);
237: register struct radix_node *t = rn_search(v, head);
238: register caddr_t cp = v + head_off;
239: register int b;
240: struct radix_node *tt;
241: /*
242: *find first bit at which v and t->rn_key differ
243: */
244: {
245: register caddr_t cp2 = t->rn_key + head_off;
246: register int cmp_res;
247: caddr_t cplim = v + vlen;
248:
249: while (cp < cplim)
250: if (*cp2++ != *cp++)
251: goto on1;
252: *dupentry = 1;
253: return t;
254: on1:
255: *dupentry = 0;
256: cmp_res = (cp[-1] ^ cp2[-1]) & 0xff;
257: for (b = (cp - v) << 3; cmp_res; b--)
258: cmp_res >>= 1;
259: }
260: {
261: register struct radix_node *p, *x = head;
262: cp = v;
263: do {
264: p = x;
265: if (cp[x->rn_off] & x->rn_bmask)
266: x = x->rn_r;
267: else x = x->rn_l;
268: } while (b > (unsigned) x->rn_b); /* x->rn_b < b && x->rn_b >= 0 */
269: #ifdef RN_DEBUG
270: if (rn_debug)
271: printf("Going In:\n"), traverse(p);
272: #endif
273: t = rn_newpair(v, b, nodes); tt = t->rn_l;
274: if ((cp[p->rn_off] & p->rn_bmask) == 0)
275: p->rn_l = t;
276: else
277: p->rn_r = t;
278: x->rn_p = t; t->rn_p = p; /* frees x, p as temp vars below */
279: if ((cp[t->rn_off] & t->rn_bmask) == 0) {
280: t->rn_r = x;
281: } else {
282: t->rn_r = tt; t->rn_l = x;
283: }
284: #ifdef RN_DEBUG
285: if (rn_debug)
286: printf("Coming out:\n"), traverse(p);
287: #endif
288: }
289: return (tt);
290: }
291:
292: struct radix_node *
293: rn_addmask(netmask, search, skip)
294: caddr_t netmask;
295: {
296: register struct radix_node *x;
297: register caddr_t cp, cplim;
298: register int b, mlen, j;
299: int maskduplicated;
300:
301: mlen = *(u_char *)netmask;
302: if (search) {
303: x = rn_search(netmask, rn_maskhead);
304: mlen = *(u_char *)netmask;
305: if (Bcmp(netmask, x->rn_key, mlen) == 0)
306: return (x);
307: }
308: R_Malloc(x, struct radix_node *, MAXKEYLEN + 2 * sizeof (*x));
309: if (x == 0)
310: return (0);
311: Bzero(x, MAXKEYLEN + 2 * sizeof (*x));
312: cp = (caddr_t)(x + 2);
313: Bcopy(netmask, cp, mlen);
314: netmask = cp;
315: x = rn_insert(netmask, rn_maskhead, &maskduplicated, x);
316: /*
317: * Calculate index of mask.
318: */
319: cplim = netmask + mlen;
320: for (cp = netmask + skip; cp < cplim; cp++)
321: if (*(u_char *)cp != 0xff)
322: break;
323: b = (cp - netmask) << 3;
324: if (cp != cplim) {
325: if (*cp != 0) {
326: gotOddMasks = 1;
327: for (j = 0x80; j; b++, j >>= 1)
328: if ((j & *cp) == 0)
329: break;
330: }
331: }
332: x->rn_b = -1 - b;
333: return (x);
334: }
335:
336: struct radix_node *
337: rn_addroute(v, netmask, head, treenodes)
338: struct radix_node *head;
339: caddr_t netmask, v;
340: struct radix_node treenodes[2];
341: {
342: register int j;
343: register caddr_t cp;
344: register struct radix_node *t, *x, *tt;
345: short b = 0, b_leaf;
346: int vlen = *(u_char *)v, mlen, keyduplicated;
347: caddr_t cplim; unsigned char *maskp;
348: struct radix_mask *m, **mp;
349: struct radix_node *saved_tt;
350:
351: /*
352: * In dealing with non-contiguous masks, there may be
353: * many different routes which have the same mask.
354: * We will find it useful to have a unique pointer to
355: * the mask to speed avoiding duplicate references at
356: * nodes and possibly save time in calculating indices.
357: */
358: if (netmask) {
359: x = rn_search(netmask, rn_maskhead);
360: mlen = *(u_char *)netmask;
361: if (Bcmp(netmask, x->rn_key, mlen) != 0) {
362: x = rn_addmask(netmask, 0, head->rn_off);
363: if (x == 0)
364: return (0);
365: }
366: netmask = x->rn_key;
367: b = -1 - x->rn_b;
368: }
369: /*
370: * Deal with duplicated keys: attach node to previous instance
371: */
372: saved_tt = tt = rn_insert(v, head, &keyduplicated, treenodes);
373: if (keyduplicated) {
374: do {
375: if (tt->rn_mask == netmask)
376: return (0);
377: t = tt;
378: } while (tt = tt->rn_dupedkey);
379: /*
380: * If the mask is not duplicated, we wouldn't
381: * find it among possible duplicate key entries
382: * anyway, so the above test doesn't hurt.
383: *
384: * XXX: we really ought to sort the masks
385: * for a duplicated key the same way as in a masklist.
386: * It is an unfortunate pain having to relocate
387: * the head of the list.
388: */
389: t->rn_dupedkey = tt = treenodes;
390: #ifdef RN_DEBUG
391: t=tt+1; tt->rn_info = rn_nodenum++; t->rn_info = rn_nodenum++;
392: tt->rn_twin = t; tt->rn_ybro = rn_clist; rn_clist = tt;
393: #endif
394: t = saved_tt;
395: tt->rn_key = (caddr_t) v;
396: tt->rn_b = -1;
397: tt->rn_flags = t->rn_flags & ~RNF_ROOT;
398: }
399: /*
400: * Put mask in tree.
401: */
402: if (netmask) {
403: tt->rn_mask = netmask;
404: tt->rn_b = x->rn_b;
405: }
406: t = saved_tt->rn_p;
407: b_leaf = -1 - t->rn_b;
408: if (t->rn_r == saved_tt) x = t->rn_l; else x = t->rn_r;
409: /* Promote general routes from below */
410: if (x->rn_b < 0) {
411: if (x->rn_mask && (x->rn_b >= b_leaf) && x->rn_mklist == 0) {
412: MKGet(m);
413: if (m) {
414: Bzero(m, sizeof *m);
415: m->rm_b = x->rn_b;
416: m->rm_mask = x->rn_mask;
417: x->rn_mklist = t->rn_mklist = m;
418: }
419: }
420: } else if (x->rn_mklist) {
421: /*
422: * Skip over masks whose index is > that of new node
423: */
424: for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist)
425: if (m->rm_b >= b_leaf)
426: break;
427: t->rn_mklist = m; *mp = 0;
428: }
429: /* Add new route to highest possible ancestor's list */
430: if ((netmask == 0) || (b > t->rn_b ))
431: return tt; /* can't lift at all */
432: b_leaf = tt->rn_b;
433: do {
434: x = t;
435: t = t->rn_p;
436: } while (b <= t->rn_b && x != head);
437: /*
438: * Search through routes associated with node to
439: * insert new route according to index.
440: * For nodes of equal index, place more specific
441: * masks first.
442: */
443: cplim = netmask + mlen;
444: for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist) {
445: if (m->rm_b < b_leaf)
446: continue;
447: if (m->rm_b > b_leaf)
448: break;
449: if (m->rm_mask == netmask) {
450: m->rm_refs++;
451: tt->rn_mklist = m;
452: return tt;
453: }
454: maskp = (u_char *)m->rm_mask;
455: for (cp = netmask; cp < cplim; cp++)
456: if (*(u_char *)cp > *maskp++)
457: goto on2;
458: }
459: on2:
460: MKGet(m);
461: if (m == 0) {
462: printf("Mask for route not entered\n");
463: return (tt);
464: }
465: Bzero(m, sizeof *m);
466: m->rm_b = b_leaf;
467: m->rm_mask = netmask;
468: m->rm_mklist = *mp;
469: *mp = m;
470: tt->rn_mklist = m;
471: return tt;
472: }
473:
474: struct radix_node *
475: rn_delete(v, netmask, head)
476: caddr_t v, netmask;
477: struct radix_node *head;
478: {
479: register struct radix_node *t, *p, *x = head;
480: register struct radix_node *tt = rn_search(v, x);
481: int b, head_off = x->rn_off, vlen = * (u_char *) v;
482: struct radix_mask *m, *saved_m, **mp;
483: struct radix_node *dupedkey, *saved_tt = tt;
484:
485: if (tt == 0 ||
486: Bcmp(v + head_off, tt->rn_key + head_off, vlen - head_off))
487: return (0);
488: /*
489: * Delete our route from mask lists.
490: */
491: if (dupedkey = tt->rn_dupedkey) {
492: if (netmask)
493: netmask = rn_search(netmask, rn_maskhead)->rn_key;
494: while (tt->rn_mask != netmask)
495: if ((tt = tt->rn_dupedkey) == 0)
496: return (0);
497: }
498: if (tt->rn_mask == 0 || (saved_m = m = tt->rn_mklist) == 0)
499: goto on1;
500: if (m->rm_mask != tt->rn_mask) {
501: printf("rn_delete: inconsistent annotation\n");
502: goto on1;
503: }
504: if (--m->rm_refs >= 0)
505: goto on1;
506: b = -1 - tt->rn_b;
507: t = saved_tt->rn_p;
508: if (b > t->rn_b)
509: goto on1; /* Wasn't lifted at all */
510: do {
511: x = t;
512: t = t->rn_p;
513: } while (b <= t->rn_b && x != head);
514: for (mp = &x->rn_mklist; m = *mp; mp = &m->rm_mklist)
515: if (m == saved_m) {
516: *mp = m->rm_mklist;
517: MKFree(m);
518: break;
519: }
520: if (m == 0)
521: printf("rn_delete: couldn't find our annotation\n");
522: on1:
523: /*
524: * Eliminate us from tree
525: */
526: if (tt->rn_flags & RNF_ROOT)
527: return (0);
528: #ifdef RN_DEBUG
529: /* Get us out of the creation list */
530: for (t = rn_clist; t && t->rn_ybro != tt; t = t->rn_ybro) {}
531: if (t) t->rn_ybro = tt->rn_ybro;
532: #endif RN_DEBUG
533: t = tt->rn_p;
534: if (dupedkey) {
535: if (tt == saved_tt) {
536: x = dupedkey; x->rn_p = t;
537: if (t->rn_l == tt) t->rn_l = x; else t->rn_r = x;
538: #ifndef RN_DEBUG
539: x++; t = tt + 1; *x = *t; p = t->rn_p;
540: #else
541: x++; b = x->rn_info; t = tt + 1; *x = *t; p = t->rn_p;
542: x->rn_info = b;
543: #endif
544: if (p->rn_l == t) p->rn_l = x; else p->rn_r = x;
545: x->rn_l->rn_p = x; x->rn_r->rn_p = x;
546: } else {
547: for (p = saved_tt; p && p->rn_dupedkey != tt;)
548: p = p->rn_dupedkey;
549: if (p) p->rn_dupedkey = tt->rn_dupedkey;
550: else printf("rn_delete: couldn't find us\n");
551: }
552: goto out;
553: }
554: if (t->rn_l == tt) x = t->rn_r; else x = t->rn_l;
555: p = t->rn_p;
556: if (p->rn_r == t) p->rn_r = x; else p->rn_l = x;
557: x->rn_p = p;
558: /*
559: * Demote routes attached to us.
560: */
561: if (t->rn_mklist) {
562: if (x->rn_b >= 0) {
563: for (mp = &x->rn_mklist; m = *mp;)
564: mp = &m->rm_mklist;
565: *mp = t->rn_mklist;
566: } else {
567: for (m = t->rn_mklist; m;) {
568: struct radix_mask *mm = m->rm_mklist;
569: if (m == x->rn_mklist && (--(m->rm_refs) < 0)) {
570: x->rn_mklist = 0;
571: MKFree(m);
572: } else
573: printf("%s %x at %x\n",
574: "rn_delete: Orphaned Mask", m, x);
575: m = mm;
576: }
577: }
578: }
579: /*
580: * We may be holding an active internal node in the tree.
581: */
582: x = tt + 1;
583: if (t != x) {
584: #ifndef RN_DEBUG
585: *t = *x;
586: #else
587: b = t->rn_info; *t = *x; t->rn_info = b;
588: #endif
589: t->rn_l->rn_p = t; t->rn_r->rn_p = t;
590: p = x->rn_p;
591: if (p->rn_l == x) p->rn_l = t; else p->rn_r = t;
592: }
593: out:
594: tt->rn_flags &= ~RNF_ACTIVE;
595: tt[1].rn_flags &= ~RNF_ACTIVE;
596: return (tt);
597: }
598: char rn_zeros[MAXKEYLEN], rn_ones[MAXKEYLEN];
599:
600: rn_inithead(head, off, af)
601: struct radix_node_head **head;
602: int off;
603: {
604: register struct radix_node_head *rnh;
605: register struct radix_node *t, *tt, *ttt;
606: if (*head)
607: return (1);
608: R_Malloc(rnh, struct radix_node_head *, sizeof (*rnh));
609: if (rnh == 0)
610: return (0);
611: Bzero(rnh, sizeof (*rnh));
612: *head = rnh;
613: t = rn_newpair(rn_zeros, off, rnh->rnh_nodes);
614: ttt = rnh->rnh_nodes + 2;
615: t->rn_r = ttt;
616: t->rn_p = t;
617: tt = t->rn_l;
618: tt->rn_flags = t->rn_flags = RNF_ROOT | RNF_ACTIVE;
619: tt->rn_b = -1 - off;
620: *ttt = *tt;
621: ttt->rn_key = rn_ones;
622: rnh->rnh_af = af;
623: rnh->rnh_treetop = t;
624: if (radix_node_head == 0) {
625: caddr_t cp = rn_ones, cplim = rn_ones + MAXKEYLEN;
626: while (cp < cplim)
627: *cp++ = -1;
628: if (rn_inithead(&radix_node_head, 0, 0) == 0) {
629: Free(rnh);
630: *head = 0;
631: return (0);
632: }
633: mask_rnhead = radix_node_head;
634: }
635: rnh->rnh_next = radix_node_head->rnh_next;
636: if (radix_node_head != rnh)
637: radix_node_head->rnh_next = rnh;
638: return (1);
639: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.