1: /*************************************************************************
2: * (C) 2007 AITNET ltd - Sofia/Bulgaria - <misho@aitnet.org>
3: * by Michael Pounov <misho@elwix.org>
4: *
5: * $Author: misho $
6: * $Id: patricia.c,v 1.2 2011/06/07 11:49:39 misho Exp $
7: *
8: **************************************************************************
9: The ELWIX and AITNET software is distributed under the following
10: terms:
11:
12: All of the documentation and software included in the ELWIX and AITNET
13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
14:
15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
16: by Michael Pounov <misho@elwix.org>. All rights reserved.
17:
18: Redistribution and use in source and binary forms, with or without
19: modification, are permitted provided that the following conditions
20: are met:
21: 1. Redistributions of source code must retain the above copyright
22: notice, this list of conditions and the following disclaimer.
23: 2. Redistributions in binary form must reproduce the above copyright
24: notice, this list of conditions and the following disclaimer in the
25: documentation and/or other materials provided with the distribution.
26: 3. All advertising materials mentioning features or use of this software
27: must display the following acknowledgement:
28: This product includes software developed by Michael Pounov <misho@elwix.org>
29: ELWIX - Embedded LightWeight unIX and its contributors.
30: 4. Neither the name of AITNET nor the names of its contributors
31: may be used to endorse or promote products derived from this software
32: without specific prior written permission.
33:
34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37: ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44: SUCH DAMAGE.
45: */
46: /*
47: * This product includes software developed by the University of Michigan,
48: * Merit Network, Inc., and their contributors.
49: *
50: * This file had been called "radix.c" in the MRT sources.
51: *
52: * I renamed it to "patricia.c" since it's not an implementation of a general
53: * radix trie. Also I pulled in various requirements from "prefix.c" and
54: * "demo.c" so that it could be used as a standalone API.
55: *
56: * Added and patched existing code by AITNET - Michael Pounov <misho@aitbg.com>
57: */
58: #include "global.h"
59:
60:
61: static int num_active_patricia;
62:
63:
64: /* { from prefix.c */
65: static inline int comp_with_mask(void *addr, void *dest, u_int mask)
66: {
67: int n, m;
68:
69: if (/* mask/8 == 0 || */ !memcmp(addr, dest, mask / 8)) {
70: n = mask / 8;
71: m = ((-1) << (8 - (mask % 8)));
72:
73: if (!(mask % 8) || (((u_char*) addr)[n] & m) == (((u_char*) dest)[n] & m))
74: return 1;
75: }
76:
77: return 0;
78: }
79:
80: /* this allows imcomplete prefix */
81: static int my_inet_pton(int af, const char *src, void *dst)
82: {
83: int i, c, val;
84: u_char xp[4] = { 0, 0, 0, 0 };
85:
86: if (af == AF_INET) {
87: for (i = 0;; i++) {
88: c = *src++;
89: if (!isdigit(c))
90: return -1;
91: val = 0;
92: do {
93: val = val * 10 + c - '0';
94: if (val > 255)
95: return 0;
96: c = *src++;
97: } while (c && isdigit(c));
98:
99: xp[i] = val;
100: if (!c)
101: break;
102: if (c != '.' || i >= 3)
103: return 0;
104: }
105:
106: memcpy(dst, xp, 4);
107: return 1;
108: #ifdef HAVE_IPV6
109: } else
110: if (af == AF_INET6) {
111: return inet_pton(af, src, dst);
112: #endif /* HAVE_IPV6 */
113: } else {
114: errno = EAFNOSUPPORT;
115: return -1;
116: }
117: }
118:
119: /*
120: * convert prefix information to ascii string with length
121: * thread safe and (almost) re-entrant implementation
122: */
123: static char *prefix_toa2x(prefix_t *prefix, char *buff, int with_len)
124: {
125: struct buffer {
126: char buffs[16][48 + 5];
127: u_int i;
128: } *buffp;
129: u_char *a;
130:
131: if (!prefix)
132: return "(Null)";
133: assert(prefix->ref_count >= 0);
134: if (!buff) {
135: #if 0
136: THREAD_SPECIFIC_DATA(struct buffer, buffp, 1);
137: #else
138: { /* for scope only */
139: static struct buffer local_buff;
140: buffp = &local_buff;
141: }
142: #endif
143: if (!buffp) {
144: /* XXX should we report an error? */
145: return NULL;
146: }
147:
148: buff = buffp->buffs[buffp->i++ % 16];
149: }
150: if (prefix->family == AF_INET) {
151: assert (prefix->bitlen <= 32);
152: a = prefix_touchar(prefix);
153: if (with_len)
154: sprintf(buff, "%d.%d.%d.%d/%d", a[0], a[1], a[2], a[3], prefix->bitlen);
155: else
156: sprintf(buff, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
157: return buff;
158: }
159: #ifdef HAVE_IPV6
160: else
161: if (prefix->family == AF_INET6) {
162: a = (char*) inet_ntop(AF_INET6, &prefix->add.sin6, buff, 48 /* a guess value */);
163: if (a && with_len) {
164: assert(prefix->bitlen <= 128);
165: sprintf(buff + strlen(buff), "/%d", prefix->bitlen);
166: }
167: return buff;
168: }
169: #endif /* HAVE_IPV6 */
170: else
171: return NULL;
172: }
173:
174: static prefix_t *New_Prefix2(int family, void *dest, int bitlen, prefix_t *prefix)
175: {
176: int dynamic_allocated = 0;
177: int default_bitlen = 32;
178:
179: #ifdef HAVE_IPV6
180: if (family == AF_INET6) {
181: default_bitlen = 128;
182: if (!prefix) {
183: prefix = calloc(1, sizeof(prefix6_t));
184: dynamic_allocated++;
185: }
186: memcpy(&prefix->add.sin6, dest, 16);
187: } else
188: #endif /* HAVE_IPV6 */
189: if (family == AF_INET) {
190: if (!prefix) {
191: prefix = calloc(1, sizeof(prefix4_t));
192: dynamic_allocated++;
193: }
194: memcpy(&prefix->add.sin, dest, 4);
195: } else
196: return NULL;
197:
198: prefix->bitlen = (bitlen >= 0) ? bitlen : default_bitlen;
199: prefix->family = family;
200: prefix->ref_count = 0;
201: if (dynamic_allocated)
202: prefix->ref_count++;
203:
204: return prefix;
205: }
206:
207: static inline prefix_t *New_Prefix(int family, void *dest, int bitlen)
208: {
209: return New_Prefix2(family, dest, bitlen, NULL);
210: }
211:
212: // ------------------------------------------------------------------------------------
213:
214: inline char *prefix_toa(prefix_t * prefix)
215: {
216: return prefix_toa2x(prefix, NULL, 0);
217: }
218:
219: inline prefix_t *ascii2prefix(int family, char *string)
220: {
221: u_long bitlen, maxbitlen = 0;
222: char *cp;
223: struct in_addr sin;
224: #ifdef HAVE_IPV6
225: struct in6_addr sin6;
226: #endif /* HAVE_IPV6 */
227: int result;
228: char save[MAXLINE];
229:
230: if (!string)
231: return (NULL);
232:
233: /* easy way to handle both families */
234: if (!family) {
235: family = AF_INET;
236: #ifdef HAVE_IPV6
237: if (strchr(string, ':'))
238: family = AF_INET6;
239: #endif /* HAVE_IPV6 */
240: }
241:
242: if (family == AF_INET)
243: maxbitlen = 32;
244: #ifdef HAVE_IPV6
245: else
246: if (family == AF_INET6)
247: maxbitlen = 128;
248: #endif /* HAVE_IPV6 */
249:
250: if ((cp = strchr(string, '/'))) {
251: bitlen = atol(cp + 1);
252: /* *cp = '\0'; */
253: /* copy the string to save. Avoid destroying the string */
254: assert(cp - string < MAXLINE);
255: memcpy(save, string, cp - string);
256: save[cp - string] = 0;
257: string = save;
258: if (bitlen < 0 || bitlen > maxbitlen)
259: bitlen = maxbitlen;
260: } else
261: bitlen = maxbitlen;
262:
263: if (family == AF_INET) {
264: if ((result = my_inet_pton(AF_INET, string, &sin)) <= 0)
265: return NULL;
266: return New_Prefix(AF_INET, &sin, bitlen);
267: }
268: #ifdef HAVE_IPV6
269: else
270: if (family == AF_INET6) {
271: if ((result = inet_pton(AF_INET6, string, &sin6)) <= 0)
272: return NULL;
273: return New_Prefix(AF_INET6, &sin6, bitlen);
274: }
275: #endif /* HAVE_IPV6 */
276: else
277: return NULL;
278: }
279:
280: inline prefix_t *Ref_Prefix(prefix_t *prefix)
281: {
282: if (!prefix)
283: return NULL;
284:
285: if (!prefix->ref_count) {
286: /* make a copy in case of a static prefix */
287: return New_Prefix2(prefix->family, &prefix->add, prefix->bitlen, NULL);
288: }
289: prefix->ref_count++;
290:
291: return prefix;
292: }
293:
294: inline void Deref_Prefix(prefix_t *prefix)
295: {
296: if (!prefix)
297: return;
298:
299: /* for secure programming, raise an assert. no static prefix can call this */
300: assert(prefix->ref_count > 0);
301: prefix->ref_count--;
302: assert(prefix->ref_count >= 0);
303: if (prefix->ref_count <= 0)
304: Delete(prefix);
305: }
306:
307: /* } */
308:
309: /* these routines support continuous mask only */
310: inline patricia_tree_t *New_Patricia(int maxbits)
311: {
312: patricia_tree_t *patricia;
313:
314: patricia = calloc(1, sizeof *patricia);
315:
316: patricia->maxbits = maxbits;
317: patricia->head = NULL;
318: patricia->num_active_node = 0;
319:
320: assert(maxbits <= PATRICIA_MAXBITS); /* XXX */
321: num_active_patricia++;
322:
323: return patricia;
324: }
325:
326:
327: /*
328: * if func is supplied, it will be called as func(node->data)
329: * before deleting the node
330: */
331: inline void Clear_Patricia(patricia_tree_t *patricia, void_fn_t func)
332: {
333: assert(patricia);
334: if (patricia->head) {
335: patricia_node_t *Xstack[PATRICIA_MAXBITS+1];
336: patricia_node_t **Xsp = Xstack;
337: patricia_node_t *Xrn = patricia->head;
338:
339: while (Xrn) {
340: patricia_node_t *l = Xrn->l;
341: patricia_node_t *r = Xrn->r;
342:
343: if (Xrn->prefix) {
344: Deref_Prefix(Xrn->prefix);
345: if (Xrn->data && func)
346: func(Xrn->data);
347: } else
348: assert(!Xrn->data);
349: Delete(Xrn);
350: patricia->num_active_node--;
351:
352: if (l) {
353: if (r)
354: *Xsp++ = r;
355: Xrn = l;
356: } else {
357: if (r)
358: Xrn = r;
359: else
360: Xrn = (Xsp != Xstack) ? *(--Xsp) : NULL;
361: }
362: }
363: }
364:
365: assert (!patricia->num_active_node);
366: /* Delete(patricia); */
367: }
368:
369: inline void Destroy_Patricia(patricia_tree_t *patricia, void_fn_t func)
370: {
371: Clear_Patricia(patricia, func);
372: Delete(patricia);
373: num_active_patricia--;
374: }
375:
376:
377: /*
378: * if func is supplied, it will be called as func(node->prefix, node->data)
379: */
380: inline void patricia_process(patricia_tree_t *patricia, void_fn_t func)
381: {
382: patricia_node_t *node;
383:
384: assert(func);
385:
386: PATRICIA_WALK(patricia->head, node) {
387: func(node->prefix, node->data);
388: } PATRICIA_WALK_END;
389: }
390:
391:
392: inline patricia_node_t *patricia_search_exact(patricia_tree_t *patricia, prefix_t *prefix)
393: {
394: patricia_node_t *node;
395: u_char *addr;
396: u_int bitlen;
397:
398: assert(patricia);
399: assert(prefix);
400: assert(prefix->bitlen <= patricia->maxbits);
401:
402: if (!patricia->head)
403: return (NULL);
404:
405: node = patricia->head;
406: addr = prefix_touchar(prefix);
407: bitlen = prefix->bitlen;
408:
409: while (node->bit < bitlen) {
410: if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
411: #ifdef PATRICIA_DEBUG
412: if (node->prefix)
413: fprintf(stderr, "patricia_search_exact: take right %s/%d\n",
414: prefix_toa(node->prefix), node->prefix->bitlen);
415: else
416: fprintf(stderr, "patricia_search_exact: take right at %d\n",
417: node->bit);
418: #endif /* PATRICIA_DEBUG */
419: node = node->r;
420: } else {
421: #ifdef PATRICIA_DEBUG
422: if (node->prefix)
423: fprintf(stderr, "patricia_search_exact: take left %s/%d\n",
424: prefix_toa(node->prefix), node->prefix->bitlen);
425: else
426: fprintf(stderr, "patricia_search_exact: take left at %d\n",
427: node->bit);
428: #endif /* PATRICIA_DEBUG */
429: node = node->l;
430: }
431:
432: if (!node)
433: return NULL;
434: }
435:
436: #ifdef PATRICIA_DEBUG
437: if (node->prefix)
438: fprintf(stderr, "patricia_search_exact: stop at %s/%d\n",
439: prefix_toa(node->prefix), node->prefix->bitlen);
440: else
441: fprintf(stderr, "patricia_search_exact: stop at %d\n", node->bit);
442: #endif /* PATRICIA_DEBUG */
443: if (node->bit > bitlen || !node->prefix)
444: return NULL;
445: assert(node->bit == bitlen);
446: assert(node->bit == node->prefix->bitlen);
447: if (comp_with_mask(prefix_touchar(node->prefix), prefix_touchar(prefix), bitlen)) {
448: #ifdef PATRICIA_DEBUG
449: fprintf(stderr, "patricia_search_exact: found %s/%d\n",
450: prefix_toa(node->prefix), node->prefix->bitlen);
451: #endif /* PATRICIA_DEBUG */
452: return node;
453: }
454:
455: return NULL;
456: }
457:
458:
459: /* if inclusive != 0, "best" may be the given prefix itself */
460: inline patricia_node_t *patricia_search_best2(patricia_tree_t *patricia, prefix_t *prefix, int inclusive)
461: {
462: patricia_node_t *node;
463: patricia_node_t *stack[PATRICIA_MAXBITS + 1];
464: u_char *addr;
465: u_int bitlen;
466: int cnt = 0;
467:
468: assert(patricia);
469: assert(prefix);
470: assert(prefix->bitlen <= patricia->maxbits);
471:
472: if (!patricia->head)
473: return NULL;
474:
475: node = patricia->head;
476: addr = prefix_touchar(prefix);
477: bitlen = prefix->bitlen;
478:
479: while (node->bit < bitlen) {
480: if (node->prefix) {
481: #ifdef PATRICIA_DEBUG
482: fprintf(stderr, "patricia_search_best: push %s/%d\n",
483: prefix_toa(node->prefix), node->prefix->bitlen);
484: #endif /* PATRICIA_DEBUG */
485: stack[cnt++] = node;
486: }
487:
488: if (BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
489: #ifdef PATRICIA_DEBUG
490: if (node->prefix)
491: fprintf(stderr, "patricia_search_best: take right %s/%d\n",
492: prefix_toa(node->prefix), node->prefix->bitlen);
493: else
494: fprintf(stderr, "patricia_search_best: take right at %d\n",
495: node->bit);
496: #endif /* PATRICIA_DEBUG */
497: node = node->r;
498: } else {
499: #ifdef PATRICIA_DEBUG
500: if (node->prefix)
501: fprintf(stderr, "patricia_search_best: take left %s/%d\n",
502: prefix_toa(node->prefix), node->prefix->bitlen);
503: else
504: fprintf(stderr, "patricia_search_best: take left at %d\n",
505: node->bit);
506: #endif /* PATRICIA_DEBUG */
507: node = node->l;
508: }
509:
510: if (!node)
511: break;
512: }
513:
514: if (inclusive && node && node->prefix)
515: stack[cnt++] = node;
516:
517: #ifdef PATRICIA_DEBUG
518: if (!node)
519: fprintf(stderr, "patricia_search_best: stop at null\n");
520: else
521: if (node->prefix)
522: fprintf(stderr, "patricia_search_best: stop at %s/%d\n",
523: prefix_toa(node->prefix), node->prefix->bitlen);
524: else
525: fprintf(stderr, "patricia_search_best: stop at %d\n", node->bit);
526: #endif /* PATRICIA_DEBUG */
527:
528: if (cnt <= 0)
529: return NULL;
530:
531: while (--cnt >= 0) {
532: node = stack[cnt];
533: #ifdef PATRICIA_DEBUG
534: fprintf(stderr, "patricia_search_best: pop %s/%d\n",
535: prefix_toa(node->prefix), node->prefix->bitlen);
536: #endif /* PATRICIA_DEBUG */
537: if (comp_with_mask(prefix_touchar(node->prefix), prefix_touchar(prefix),
538: node->prefix->bitlen)) {
539: #ifdef PATRICIA_DEBUG
540: fprintf(stderr, "patricia_search_best: found %s/%d\n",
541: prefix_toa(node->prefix), node->prefix->bitlen);
542: #endif /* PATRICIA_DEBUG */
543: return node;
544: }
545: }
546:
547: return NULL;
548: }
549:
550: inline patricia_node_t *patricia_search_best(patricia_tree_t *patricia, prefix_t *prefix)
551: {
552: return patricia_search_best2(patricia, prefix, 1);
553: }
554:
555:
556: inline patricia_node_t *patricia_lookup(patricia_tree_t *patricia, prefix_t *prefix)
557: {
558: patricia_node_t *node, *new_node, *parent, *glue;
559: u_char *addr, *test_addr;
560: u_int bitlen, check_bit, differ_bit;
561: int i, j, r;
562:
563: assert(patricia);
564: assert(prefix);
565: assert(prefix->bitlen <= patricia->maxbits);
566:
567: if (!patricia->head) {
568: node = calloc(1, sizeof *node);
569: node->bit = prefix->bitlen;
570: node->prefix = Ref_Prefix(prefix);
571: node->parent = NULL;
572: node->l = node->r = NULL;
573: node->data = NULL;
574: patricia->head = node;
575: #ifdef PATRICIA_DEBUG
576: fprintf(stderr, "patricia_lookup: new_node #0 %s/%d (head)\n",
577: prefix_toa(prefix), prefix->bitlen);
578: #endif /* PATRICIA_DEBUG */
579: patricia->num_active_node++;
580: return node;
581: }
582:
583: addr = prefix_touchar(prefix);
584: bitlen = prefix->bitlen;
585: node = patricia->head;
586:
587: while (node->bit < bitlen || !node->prefix) {
588: if (node->bit < patricia->maxbits &&
589: BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
590: if (!node->r)
591: break;
592: #ifdef PATRICIA_DEBUG
593: if (node->prefix)
594: fprintf(stderr, "patricia_lookup: take right %s/%d\n",
595: prefix_toa(node->prefix), node->prefix->bitlen);
596: else
597: fprintf(stderr, "patricia_lookup: take right at %d\n", node->bit);
598: #endif /* PATRICIA_DEBUG */
599: node = node->r;
600: } else {
601: if (!node->l)
602: break;
603: #ifdef PATRICIA_DEBUG
604: if (node->prefix)
605: fprintf(stderr, "patricia_lookup: take left %s/%d\n",
606: prefix_toa(node->prefix), node->prefix->bitlen);
607: else
608: fprintf(stderr, "patricia_lookup: take left at %d\n", node->bit);
609: #endif /* PATRICIA_DEBUG */
610: node = node->l;
611: }
612:
613: assert(node);
614: }
615:
616: assert(node->prefix);
617: #ifdef PATRICIA_DEBUG
618: fprintf(stderr, "patricia_lookup: stop at %s/%d\n",
619: prefix_toa(node->prefix), node->prefix->bitlen);
620: #endif /* PATRICIA_DEBUG */
621:
622: test_addr = prefix_touchar(node->prefix);
623: /* find the first bit different */
624: check_bit = (node->bit < bitlen) ? node->bit : bitlen;
625: differ_bit = 0;
626: for (i = 0; i * 8 < check_bit; i++) {
627: if (!(r = (addr[i] ^ test_addr[i]))) {
628: differ_bit = (i + 1) * 8;
629: continue;
630: }
631: /* I know the better way, but for now */
632: for (j = 0; j < 8; j++) {
633: if (BIT_TEST(r, (0x80 >> j)))
634: break;
635: }
636: /* must be found */
637: assert(j < 8);
638: differ_bit = i * 8 + j;
639: break;
640: }
641:
642: if (differ_bit > check_bit)
643: differ_bit = check_bit;
644: #ifdef PATRICIA_DEBUG
645: fprintf(stderr, "patricia_lookup: differ_bit %d\n", differ_bit);
646: #endif /* PATRICIA_DEBUG */
647:
648: parent = node->parent;
649: while (parent && parent->bit >= differ_bit) {
650: node = parent;
651: parent = node->parent;
652: #ifdef PATRICIA_DEBUG
653: if (node->prefix)
654: fprintf(stderr, "patricia_lookup: up to %s/%d\n",
655: prefix_toa(node->prefix), node->prefix->bitlen);
656: else
657: fprintf(stderr, "patricia_lookup: up to %d\n", node->bit);
658: #endif /* PATRICIA_DEBUG */
659: }
660:
661: if (differ_bit == bitlen && node->bit == bitlen) {
662: if (node->prefix) {
663: #ifdef PATRICIA_DEBUG
664: fprintf(stderr, "patricia_lookup: found %s/%d\n",
665: prefix_toa(node->prefix), node->prefix->bitlen);
666: #endif /* PATRICIA_DEBUG */
667: return node;
668: }
669: node->prefix = Ref_Prefix(prefix);
670: #ifdef PATRICIA_DEBUG
671: fprintf(stderr, "patricia_lookup: new node #1 %s/%d (glue mod)\n",
672: prefix_toa(prefix), prefix->bitlen);
673: #endif /* PATRICIA_DEBUG */
674: assert(!node->data);
675: return node;
676: }
677:
678: new_node = calloc(1, sizeof *new_node);
679: new_node->bit = prefix->bitlen;
680: new_node->prefix = Ref_Prefix (prefix);
681: new_node->parent = NULL;
682: new_node->l = new_node->r = NULL;
683: new_node->data = NULL;
684: patricia->num_active_node++;
685:
686: if (node->bit == differ_bit) {
687: new_node->parent = node;
688: if (node->bit < patricia->maxbits &&
689: BIT_TEST(addr[node->bit >> 3], 0x80 >> (node->bit & 0x07))) {
690: assert(!node->r);
691: node->r = new_node;
692: } else {
693: assert(!node->l);
694: node->l = new_node;
695: }
696: #ifdef PATRICIA_DEBUG
697: fprintf(stderr, "patricia_lookup: new_node #2 %s/%d (child)\n",
698: prefix_toa(prefix), prefix->bitlen);
699: #endif /* PATRICIA_DEBUG */
700: return new_node;
701: }
702:
703: if (bitlen == differ_bit) {
704: if (bitlen < patricia->maxbits &&
705: BIT_TEST(test_addr[bitlen >> 3], 0x80 >> (bitlen & 0x07)))
706: new_node->r = node;
707: else
708: new_node->l = node;
709: new_node->parent = node->parent;
710: if (!node->parent) {
711: assert(patricia->head == node);
712: patricia->head = new_node;
713: } else
714: if (node->parent->r == node)
715: node->parent->r = new_node;
716: else
717: node->parent->l = new_node;
718: node->parent = new_node;
719: #ifdef PATRICIA_DEBUG
720: fprintf(stderr, "patricia_lookup: new_node #3 %s/%d (parent)\n",
721: prefix_toa(prefix), prefix->bitlen);
722: #endif /* PATRICIA_DEBUG */
723: } else {
724: glue = calloc(1, sizeof *glue);
725: glue->bit = differ_bit;
726: glue->prefix = NULL;
727: glue->parent = node->parent;
728: glue->data = NULL;
729: patricia->num_active_node++;
730:
731: if (differ_bit < patricia->maxbits &&
732: BIT_TEST(addr[differ_bit >> 3], 0x80 >> (differ_bit & 0x07))) {
733: glue->r = new_node;
734: glue->l = node;
735: } else {
736: glue->r = node;
737: glue->l = new_node;
738: }
739: new_node->parent = glue;
740:
741: if (!node->parent) {
742: assert(patricia->head == node);
743: patricia->head = glue;
744: } else
745: if (node->parent->r == node)
746: node->parent->r = glue;
747: else
748: node->parent->l = glue;
749: node->parent = glue;
750: #ifdef PATRICIA_DEBUG
751: fprintf(stderr, "patricia_lookup: new_node #4 %s/%d (glue+node)\n",
752: prefix_toa(prefix), prefix->bitlen);
753: #endif /* PATRICIA_DEBUG */
754: }
755:
756: return new_node;
757: }
758:
759:
760: inline void patricia_remove(patricia_tree_t *patricia, patricia_node_t *node)
761: {
762: patricia_node_t *parent, *child;
763:
764: assert(patricia);
765: assert(node);
766:
767: if (node->r && node->l) {
768: #ifdef PATRICIA_DEBUG
769: fprintf(stderr, "patricia_remove: #0 %s/%d (r & l)\n",
770: prefix_toa(node->prefix), node->prefix->bitlen);
771: #endif /* PATRICIA_DEBUG */
772:
773: /* this might be a placeholder node -- have to check and make sure
774: * there is a prefix aossciated with it ! */
775: if (node->prefix)
776: Deref_Prefix(node->prefix);
777: node->prefix = NULL;
778: /* Also I needed to clear data pointer -- masaki */
779: node->data = NULL;
780: return;
781: }
782:
783: if (!node->r && !node->l) {
784: #ifdef PATRICIA_DEBUG
785: fprintf(stderr, "patricia_remove: #1 %s/%d (!r & !l)\n",
786: prefix_toa(node->prefix), node->prefix->bitlen);
787: #endif /* PATRICIA_DEBUG */
788: parent = node->parent;
789: Deref_Prefix(node->prefix);
790: Delete(node);
791: patricia->num_active_node--;
792:
793: if (!parent) {
794: assert(patricia->head == node);
795: patricia->head = NULL;
796: return;
797: }
798:
799: if (parent->r == node) {
800: parent->r = NULL;
801: child = parent->l;
802: } else {
803: assert(parent->l == node);
804: parent->l = NULL;
805: child = parent->r;
806: }
807:
808: if (parent->prefix)
809: return;
810:
811: /* we need to remove parent too */
812: if (!parent->parent) {
813: assert(patricia->head == parent);
814: patricia->head = child;
815: } else
816: if (parent->parent->r == parent)
817: parent->parent->r = child;
818: else {
819: assert(parent->parent->l == parent);
820: parent->parent->l = child;
821: }
822: child->parent = parent->parent;
823: Delete(parent);
824: patricia->num_active_node--;
825: return;
826: }
827:
828: #ifdef PATRICIA_DEBUG
829: fprintf(stderr, "patricia_remove: #2 %s/%d (r ^ l)\n",
830: prefix_toa(node->prefix), node->prefix->bitlen);
831: #endif /* PATRICIA_DEBUG */
832: if (node->r)
833: child = node->r;
834: else {
835: assert(node->l);
836: child = node->l;
837: }
838: parent = node->parent;
839: child->parent = parent;
840:
841: Deref_Prefix(node->prefix);
842: Delete(node);
843: patricia->num_active_node--;
844:
845: if (!parent) {
846: assert(patricia->head == node);
847: patricia->head = child;
848: return;
849: }
850:
851: if (parent->r == node)
852: parent->r = child;
853: else {
854: assert(parent->l == node);
855: parent->l = child;
856: }
857: }
858:
859: /* { from demo.c */
860:
861: inline void lookup_then_remove(patricia_tree_t *tree, char *string)
862: {
863: patricia_node_t *node;
864:
865: if ((node = try_search_exact(tree, string)))
866: patricia_remove(tree, node);
867: }
868:
869: inline patricia_node_t *make_and_lookup(patricia_tree_t *tree, char *string)
870: {
871: prefix_t *prefix;
872: patricia_node_t *node;
873:
874: prefix = ascii2prefix(AF_INET, string);
875: #ifdef PATRICIA_DEBUG
876: printf("make_and_lookup: %s/%d\n", prefix_toa(prefix), prefix->bitlen);
877: #endif
878: node = patricia_lookup(tree, prefix);
879: Deref_Prefix(prefix);
880:
881: return node;
882: }
883:
884: inline patricia_node_t *try_search_exact(patricia_tree_t *tree, char *string)
885: {
886: prefix_t *prefix;
887: patricia_node_t *node;
888:
889: prefix = ascii2prefix(AF_INET, string);
890: #ifdef PATRICIA_DEBUG
891: printf("try_search_exact: %s/%d\n", prefix_toa(prefix), prefix->bitlen);
892: #endif
893: node = patricia_search_exact(tree, prefix);
894: #ifdef PATRICIA_DEBUG
895: if (!node)
896: printf("try_search_exact: not found\n");
897: else
898: printf("try_search_exact: %s/%d found\n", prefix_toa(node->prefix), node->prefix->bitlen);
899: #endif
900: Deref_Prefix(prefix);
901:
902: return node;
903: }
904:
905: inline patricia_node_t *try_search_best(patricia_tree_t *tree, char *string)
906: {
907: prefix_t *prefix;
908: patricia_node_t *node;
909:
910: prefix = ascii2prefix(AF_INET, string);
911: #ifdef PATRICIA_DEBUG
912: printf("try_search_best: %s/%d\n", prefix_toa(prefix), prefix->bitlen);
913: #endif
914: node = patricia_search_best(tree, prefix);
915: #ifdef PATRICIA_DEBUG
916: if (!node)
917: printf("try_search_best: not found\n");
918: else
919: printf("try_search_best: %s/%d found\n", prefix_toa(node->prefix), node->prefix->bitlen);
920: #endif
921: Deref_Prefix(prefix);
922:
923: return node;
924: }
925:
926: /* } */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>