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