1 /* $OpenBSD: rde_trie.c,v 1.17 2022/12/28 21:30:16 jmc Exp $ */
2
3 /*
4 * Copyright (c) 2018 Claudio Jeker <claudio@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 #include <sys/types.h>
19 #include <sys/queue.h>
20
21 #include <netinet/in.h>
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "bgpd.h"
28 #include "rde.h"
29
30 /*
31 * Bitwise compressed trie for prefix-sets.
32 * Since the trie is path compressed the traversing function needs to check
33 * that the lookup is still on path before taking a branch.
34 * There are two types of nodes in the trie. Internal branch nodes and real
35 * nodes. Internal nodes are added when needed because off path nodes are being
36 * inserted and are just used for branching.
37 * During lookup every node defines which bit is checked for branching. This
38 * offset is strictly increasing. For IPv4 the maximum is therefore 32 levels.
39 * Every node checks the bit at position plen to decide which branch to take.
40 * The real nodes also include a prefixlen mask which represents the prefixlen
41 * range that was defined. The prefixlen mask for IPv4 only has 32 bits but
42 * the prefixlen range is from 0 - 32 which needs 33bits. Now prefixlen 0 is
43 * special and only one element -- the default route -- can have prefixlen 0.
44 * So this default route is added as a flag to the trie_head and needs to be
45 * checked independent of the trie when doing a lookup.
46 * On insertion a prefix is added with its prefixlen plen and a min & max
47 * for the prefixlen range. The following precondition needs to hold
48 * plen <= min <= max
49 * To only match the prefix itself min and max are set to plen.
50 * If a same prefix (addr/plen) is added to the trie but with different
51 * min & max values then the masks of both nodes are merged with a binary OR.
52 * The match function returns true the moment the first node is found which
53 * covers the looked up prefix and where the prefixlen mask matches for the
54 * looked up prefixlen. The moment the plen of a node is bigger than the
55 * prefixlen of the looked up prefix the search can be stopped since
56 * there will be no match.
57 */
58 struct tentry_v4 {
59 struct tentry_v4 *trie[2];
60 struct set_table *set; /* for roa source-as set */
61 struct in_addr addr;
62 struct in_addr plenmask;
63 uint8_t plen;
64 uint8_t node;
65 };
66
67 struct tentry_v6 {
68 struct tentry_v6 *trie[2];
69 struct set_table *set; /* for roa source-as set */
70 struct in6_addr addr;
71 struct in6_addr plenmask;
72 uint8_t plen;
73 uint8_t node;
74 };
75
76 /*
77 * Find first different bit between a & b starting from the MSB,
78 * a & b have to be different.
79 */
80 static int
inet4findmsb(struct in_addr * a,struct in_addr * b)81 inet4findmsb(struct in_addr *a, struct in_addr *b)
82 {
83 int r = 0;
84 uint32_t v;
85
86 v = ntohl(a->s_addr ^ b->s_addr);
87 if (v > 0xffff) { r += 16; v >>= 16; }
88 if (v > 0x00ff) { r += 8; v >>= 8; }
89 if (v > 0x000f) { r += 4; v >>= 4; }
90 if (v > 0x0003) { r += 2; v >>= 2; }
91 if (v > 0x0001) { r += 1; }
92
93 return 31 - r;
94 }
95
96 /*
97 * Find first different bit between a & b starting from the MSB,
98 * a & b have to be different.
99 */
100 static int
inet6findmsb(struct in6_addr * a,struct in6_addr * b)101 inet6findmsb(struct in6_addr *a, struct in6_addr *b)
102 {
103 int r = 0;
104 uint8_t i, x;
105
106 for (i = 0; i < sizeof(*a) && a->s6_addr[i] == b->s6_addr[i]; i++)
107 ;
108 /* first different octet */
109 x = a->s6_addr[i] ^ b->s6_addr[i];
110
111 /* first different bit */
112 if (x > 0xf) { r += 4; x >>= 4; }
113 if (x > 0x3) { r += 2; x >>= 2; }
114 if (x > 0x1) { r += 1; }
115
116 return i * 8 + 7 - r;
117 }
118
119 static int
inet4isset(struct in_addr * addr,uint8_t bit)120 inet4isset(struct in_addr *addr, uint8_t bit)
121 {
122 return addr->s_addr & htonl(1U << (31 - bit));
123 }
124
125 static int
inet6isset(struct in6_addr * addr,uint8_t bit)126 inet6isset(struct in6_addr *addr, uint8_t bit)
127 {
128 return addr->s6_addr[bit / 8] & (0x80 >> (bit % 8));
129 }
130
131 static void
inet4setbit(struct in_addr * addr,uint8_t bit)132 inet4setbit(struct in_addr *addr, uint8_t bit)
133 {
134 /* bit 0 sets the MSB and 31 sets the LSB */
135 addr->s_addr |= htonl(1U << (31 - bit));
136 }
137
138 static void
inet6setbit(struct in6_addr * addr,uint8_t bit)139 inet6setbit(struct in6_addr *addr, uint8_t bit)
140 {
141 addr->s6_addr[bit / 8] |= (0x80 >> (bit % 8));
142 }
143
144 static struct tentry_v4 *
trie_add_v4(struct trie_head * th,struct in_addr * prefix,uint8_t plen)145 trie_add_v4(struct trie_head *th, struct in_addr *prefix, uint8_t plen)
146 {
147 struct tentry_v4 *n, *new, *b, **prev;
148 struct in_addr p;
149
150 inet4applymask(&p, prefix, plen);
151
152 /* walk tree finding spot to insert */
153 prev = &th->root_v4;
154 n = *prev;
155 while (n) {
156 struct in_addr mp;
157 uint8_t minlen;
158
159 minlen = n->plen > plen ? plen : n->plen;
160 inet4applymask(&mp, &p, minlen);
161 if (n->addr.s_addr != mp.s_addr) {
162 /*
163 * out of path, insert intermediary node between
164 * np and n, then insert n and new node there
165 */
166 if ((b = calloc(1, sizeof(*b))) == NULL)
167 return NULL;
168 rdemem.pset_cnt++;
169 rdemem.pset_size += sizeof(*b);
170 b->plen = inet4findmsb(&n->addr, &mp);
171 inet4applymask(&b->addr, &n->addr, b->plen);
172
173 *prev = b;
174 if (inet4isset(&n->addr, b->plen)) {
175 b->trie[1] = n;
176 prev = &b->trie[0];
177 } else {
178 b->trie[0] = n;
179 prev = &b->trie[1];
180 }
181 n = NULL;
182 break;
183 }
184
185 if (n->plen > plen) {
186 /* n is more specific, just insert new in between */
187 break;
188 }
189
190 if (n->plen == plen) {
191 /* matching node, adjust */
192 if (n->node == 0)
193 th->v4_cnt++;
194 n->node = 1;
195 return n;
196 }
197
198 /* no need to check for n->plen == 32 because of above if */
199 if (inet4isset(&p, n->plen))
200 prev = &n->trie[1];
201 else
202 prev = &n->trie[0];
203 n = *prev;
204 }
205
206 /* create new node */
207 if ((new = calloc(1, sizeof(*new))) == NULL)
208 return NULL;
209 th->v4_cnt++;
210 rdemem.pset_cnt++;
211 rdemem.pset_size += sizeof(*new);
212 new->addr = p;
213 new->plen = plen;
214 new->node = 1;
215
216 /* link node */
217 *prev = new;
218 if (n) {
219 if (inet4isset(&n->addr, new->plen))
220 new->trie[1] = n;
221 else
222 new->trie[0] = n;
223 }
224 return new;
225 }
226
227 static struct tentry_v6 *
trie_add_v6(struct trie_head * th,struct in6_addr * prefix,uint8_t plen)228 trie_add_v6(struct trie_head *th, struct in6_addr *prefix, uint8_t plen)
229 {
230 struct tentry_v6 *n, *new, *b, **prev;
231 struct in6_addr p;
232
233 inet6applymask(&p, prefix, plen);
234
235 /* walk tree finding spot to insert */
236 prev = &th->root_v6;
237 n = *prev;
238 while (n) {
239 struct in6_addr mp;
240 uint8_t minlen;
241
242 minlen = n->plen > plen ? plen : n->plen;
243 inet6applymask(&mp, &p, minlen);
244 if (memcmp(&n->addr, &mp, sizeof(mp)) != 0) {
245 /*
246 * out of path, insert intermediary node between
247 * np and n, then insert n and new node there
248 */
249 if ((b = calloc(1, sizeof(*b))) == NULL)
250 return NULL;
251 rdemem.pset_cnt++;
252 rdemem.pset_size += sizeof(*b);
253 b->plen = inet6findmsb(&n->addr, &mp);
254 inet6applymask(&b->addr, &n->addr, b->plen);
255
256 *prev = b;
257 if (inet6isset(&n->addr, b->plen)) {
258 b->trie[1] = n;
259 prev = &b->trie[0];
260 } else {
261 b->trie[0] = n;
262 prev = &b->trie[1];
263 }
264 n = NULL;
265 break;
266 }
267
268 if (n->plen > plen) {
269 /* n is more specific, just insert new in between */
270 break;
271 }
272
273 if (n->plen == plen) {
274 /* matching node, adjust */
275 if (n->node == 0)
276 th->v6_cnt++;
277 n->node = 1;
278 return n;
279 }
280
281 /* no need to check for n->plen == 128 because of above if */
282 if (inet6isset(&p, n->plen))
283 prev = &n->trie[1];
284 else
285 prev = &n->trie[0];
286 n = *prev;
287 }
288
289 /* create new node */
290 if ((new = calloc(1, sizeof(*new))) == NULL)
291 return NULL;
292 th->v6_cnt++;
293 rdemem.pset_cnt++;
294 rdemem.pset_size += sizeof(*new);
295 new->addr = p;
296 new->plen = plen;
297 new->node = 1;
298
299 /* link node */
300 *prev = new;
301 if (n) {
302 if (inet6isset(&n->addr, new->plen))
303 new->trie[1] = n;
304 else
305 new->trie[0] = n;
306 }
307 return new;
308 }
309
310 /*
311 * Insert prefix/plen into the trie with a prefixlen mask covering min - max.
312 * If plen == min == max then only the prefix/plen will match and no longer
313 * match is possible. Else all prefixes under prefix/plen with a prefixlen
314 * between min and max will match.
315 */
316 int
trie_add(struct trie_head * th,struct bgpd_addr * prefix,uint8_t plen,uint8_t min,uint8_t max)317 trie_add(struct trie_head *th, struct bgpd_addr *prefix, uint8_t plen,
318 uint8_t min, uint8_t max)
319 {
320 struct tentry_v4 *n4;
321 struct tentry_v6 *n6;
322 uint8_t i;
323
324 /* precondition plen <= min <= max */
325 if (plen > min || min > max)
326 return -1;
327 if (prefix->aid != AID_INET && prefix->aid != AID_INET6)
328 return -1;
329
330 /*
331 * Check for default route, this is special cased since prefixlen 0
332 * can't be checked in the prefixlen mask plenmask. Also there is
333 * only one default route so using a flag for this works.
334 */
335 if (min == 0) {
336 if (prefix->aid == AID_INET)
337 th->match_default_v4 = 1;
338 else
339 th->match_default_v6 = 1;
340
341 if (max == 0) /* just the default route */
342 return 0;
343 min = 1;
344 }
345
346 switch (prefix->aid) {
347 case AID_INET:
348 if (max > 32)
349 return -1;
350
351 n4 = trie_add_v4(th, &prefix->v4, plen);
352 if (n4 == NULL)
353 return -1;
354 /*
355 * The prefixlen min - max goes from 1 to 32 but the bitmask
356 * starts at 0 and so all bits are set with an offset of -1.
357 * The default /0 route is handled specially above.
358 */
359 for (i = min; i <= max; i++)
360 inet4setbit(&n4->plenmask, i - 1);
361 break;
362 case AID_INET6:
363 if (max > 128)
364 return -1;
365
366 n6 = trie_add_v6(th, &prefix->v6, plen);
367 if (n6 == NULL)
368 return -1;
369
370 /* See above for the - 1 reason. */
371 for (i = min; i <= max; i++)
372 inet6setbit(&n6->plenmask, i - 1);
373 break;
374 }
375 return 0;
376 }
377
378 /*
379 * Insert a ROA entry for prefix/plen. The prefix will insert a set with
380 * source_as and the maxlen as data. This makes it possible to validate if a
381 * prefix is matching this ROA record. It is possible to insert prefixes with
382 * source_as = 0. These entries will never return ROA_VALID on check and can
383 * be used to cover a large prefix as ROA_INVALID unless a more specific route
384 * is a match.
385 */
386 int
trie_roa_add(struct trie_head * th,struct roa * roa)387 trie_roa_add(struct trie_head *th, struct roa *roa)
388 {
389 struct tentry_v4 *n4;
390 struct tentry_v6 *n6;
391 struct set_table **stp;
392 struct roa_set rs, *rsp;
393
394 /* ignore possible default route since it does not make sense */
395
396 switch (roa->aid) {
397 case AID_INET:
398 if (roa->prefixlen > 32)
399 return -1;
400
401 n4 = trie_add_v4(th, &roa->prefix.inet, roa->prefixlen);
402 if (n4 == NULL)
403 return -1;
404 stp = &n4->set;
405 break;
406 case AID_INET6:
407 if (roa->prefixlen > 128)
408 return -1;
409
410 n6 = trie_add_v6(th, &roa->prefix.inet6, roa->prefixlen);
411 if (n6 == NULL)
412 return -1;
413 stp = &n6->set;
414 break;
415 default:
416 /* anything else fails */
417 return -1;
418 }
419
420 if (*stp == NULL)
421 if ((*stp = set_new(1, sizeof(rs))) == NULL)
422 return -1;
423
424 /* merge sets with same key, longer maxlen wins */
425 if ((rsp = set_match(*stp, roa->asnum)) != NULL) {
426 if (rsp->maxlen < roa->maxlen)
427 rsp->maxlen = roa->maxlen;
428 } else {
429 rs.as = roa->asnum;
430 rs.maxlen = roa->maxlen;
431 if (set_add(*stp, &rs, 1) != 0)
432 return -1;
433 /* prep data so that set_match works */
434 set_prep(*stp);
435 }
436
437 return 0;
438 }
439
440 static void
trie_free_v4(struct tentry_v4 * n)441 trie_free_v4(struct tentry_v4 *n)
442 {
443 if (n == NULL)
444 return;
445 trie_free_v4(n->trie[0]);
446 trie_free_v4(n->trie[1]);
447 set_free(n->set);
448 free(n);
449 rdemem.pset_cnt--;
450 rdemem.pset_size -= sizeof(*n);
451 }
452
453 static void
trie_free_v6(struct tentry_v6 * n)454 trie_free_v6(struct tentry_v6 *n)
455 {
456 if (n == NULL)
457 return;
458 trie_free_v6(n->trie[0]);
459 trie_free_v6(n->trie[1]);
460 set_free(n->set);
461 free(n);
462 rdemem.pset_cnt--;
463 rdemem.pset_size -= sizeof(*n);
464 }
465
466 void
trie_free(struct trie_head * th)467 trie_free(struct trie_head *th)
468 {
469 trie_free_v4(th->root_v4);
470 trie_free_v6(th->root_v6);
471 memset(th, 0, sizeof(*th));
472 }
473
474 static int
trie_match_v4(struct trie_head * th,struct in_addr * prefix,uint8_t plen,int orlonger)475 trie_match_v4(struct trie_head *th, struct in_addr *prefix, uint8_t plen,
476 int orlonger)
477 {
478 struct tentry_v4 *n;
479
480 if (plen == 0) {
481 /* special handling for default route */
482 return th->match_default_v4;
483 }
484
485 n = th->root_v4;
486 while (n) {
487 struct in_addr mp;
488
489 if (n->plen > plen)
490 break; /* too specific, no match possible */
491
492 inet4applymask(&mp, prefix, n->plen);
493 if (n->addr.s_addr != mp.s_addr)
494 break; /* off path, no match possible */
495
496 /* the match covers all larger prefixlens */
497 if (n->node && orlonger)
498 return 1;
499
500 /* plen is from 1 - 32 but the bitmask starts with 0 */
501 if (n->node && inet4isset(&n->plenmask, plen - 1))
502 return 1; /* prefixlen allowed, match */
503
504 if (n->plen == 32)
505 break; /* can't go deeper */
506 if (inet4isset(prefix, n->plen))
507 n = n->trie[1];
508 else
509 n = n->trie[0];
510 }
511
512 return 0;
513 }
514
515 static int
trie_match_v6(struct trie_head * th,struct in6_addr * prefix,uint8_t plen,int orlonger)516 trie_match_v6(struct trie_head *th, struct in6_addr *prefix, uint8_t plen,
517 int orlonger)
518 {
519 struct tentry_v6 *n;
520
521 if (plen == 0) {
522 /* special handling for default route */
523 return th->match_default_v6;
524 }
525
526 n = th->root_v6;
527 while (n) {
528 struct in6_addr mp;
529
530 if (n->plen > plen)
531 break; /* too specific, no match possible */
532
533 inet6applymask(&mp, prefix, n->plen);
534 if (memcmp(&n->addr, &mp, sizeof(mp)) != 0)
535 break; /* off path, no match possible */
536
537 /* the match covers all larger prefixlens */
538 if (n->node && orlonger)
539 return 1;
540
541 /* plen is from 1 - 128 but the bitmask starts with 0 */
542 if (n->node && inet6isset(&n->plenmask, plen - 1))
543 return 1; /* prefixlen allowed, match */
544
545 if (n->plen == 128)
546 break; /* can't go deeper */
547 if (inet6isset(prefix, n->plen))
548 n = n->trie[1];
549 else
550 n = n->trie[0];
551 }
552 return 0;
553 }
554
555 /* find first matching element in the trie for prefix "prefix/plen" */
556 int
trie_match(struct trie_head * th,struct bgpd_addr * prefix,uint8_t plen,int orlonger)557 trie_match(struct trie_head *th, struct bgpd_addr *prefix, uint8_t plen,
558 int orlonger)
559 {
560 switch (prefix->aid) {
561 case AID_INET:
562 return trie_match_v4(th, &prefix->v4, plen, orlonger);
563 case AID_INET6:
564 return trie_match_v6(th, &prefix->v6, plen, orlonger);
565 default:
566 /* anything else is no match */
567 return 0;
568 }
569 }
570
571 static int
trie_roa_check_v4(struct trie_head * th,struct in_addr * prefix,uint8_t plen,uint32_t as)572 trie_roa_check_v4(struct trie_head *th, struct in_addr *prefix, uint8_t plen,
573 uint32_t as)
574 {
575 struct tentry_v4 *n;
576 struct roa_set *rs;
577 int validity = ROA_NOTFOUND;
578
579 /* ignore possible default route since it does not make sense */
580
581 n = th->root_v4;
582 while (n) {
583 struct in_addr mp;
584
585 if (n->plen > plen)
586 break; /* too specific, no match possible */
587
588 inet4applymask(&mp, prefix, n->plen);
589 if (n->addr.s_addr != mp.s_addr)
590 break; /* off path, no other match possible */
591
592 if (n->node) {
593 /*
594 * The prefix is covered by this roa node
595 * therefore invalid unless roa_set matches.
596 */
597 validity = ROA_INVALID;
598
599 /* AS_NONE can never match, so don't try */
600 if (as != AS_NONE) {
601 if ((rs = set_match(n->set, as)) != NULL) {
602 if (plen == n->plen || plen <= rs->maxlen)
603 return ROA_VALID;
604 }
605 }
606 }
607
608 if (n->plen == 32)
609 break; /* can't go deeper */
610 if (inet4isset(prefix, n->plen))
611 n = n->trie[1];
612 else
613 n = n->trie[0];
614 }
615
616 return validity;
617 }
618
619 static int
trie_roa_check_v6(struct trie_head * th,struct in6_addr * prefix,uint8_t plen,uint32_t as)620 trie_roa_check_v6(struct trie_head *th, struct in6_addr *prefix, uint8_t plen,
621 uint32_t as)
622 {
623 struct tentry_v6 *n;
624 struct roa_set *rs;
625 int validity = ROA_NOTFOUND;
626
627 /* ignore possible default route since it does not make sense */
628
629 n = th->root_v6;
630 while (n) {
631 struct in6_addr mp;
632
633 if (n->plen > plen)
634 break; /* too specific, no match possible */
635
636 inet6applymask(&mp, prefix, n->plen);
637 if (memcmp(&n->addr, &mp, sizeof(mp)) != 0)
638 break; /* off path, no other match possible */
639
640 if (n->node) {
641 /*
642 * This prefix is covered by this roa node.
643 * Therefore invalid unless proven otherwise.
644 */
645 validity = ROA_INVALID;
646
647 /* AS_NONE can never match, so don't try */
648 if (as != AS_NONE) {
649 if ((rs = set_match(n->set, as)) != NULL)
650 if (plen == n->plen || plen <= rs->maxlen)
651 return ROA_VALID;
652 }
653 }
654
655 if (n->plen == 128)
656 break; /* can't go deeper */
657 if (inet6isset(prefix, n->plen))
658 n = n->trie[1];
659 else
660 n = n->trie[0];
661 }
662
663 return validity;
664 }
665
666 /*
667 * Do a ROA (Route Origin Validation) check. Look for elements in the trie
668 * which cover prefix "prefix/plen" and match the source-as as.
669 * AS_NONE can be used when the source-as is unknown (e.g. AS_SET).
670 * The check will then only return ROA_NOTFOUND or ROA_INVALID depending if
671 * the prefix is covered by the ROA.
672 */
673 int
trie_roa_check(struct trie_head * th,struct bgpd_addr * prefix,uint8_t plen,uint32_t as)674 trie_roa_check(struct trie_head *th, struct bgpd_addr *prefix, uint8_t plen,
675 uint32_t as)
676 {
677 /* valid, invalid, unknown */
678 switch (prefix->aid) {
679 case AID_INET:
680 return trie_roa_check_v4(th, &prefix->v4, plen, as);
681 case AID_INET6:
682 return trie_roa_check_v6(th, &prefix->v6, plen, as);
683 default:
684 /* anything else is not-found */
685 return ROA_NOTFOUND;
686 }
687 }
688
689 static int
trie_equal_v4(struct tentry_v4 * a,struct tentry_v4 * b)690 trie_equal_v4(struct tentry_v4 *a, struct tentry_v4 *b)
691 {
692 if (a == NULL && b == NULL)
693 return 1;
694 if (a == NULL || b == NULL)
695 return 0;
696
697 if (a->addr.s_addr != b->addr.s_addr ||
698 a->plen != b->plen ||
699 a->node != b->node ||
700 a->plenmask.s_addr != b->plenmask.s_addr)
701 return 0;
702
703 if (set_equal(a->set, b->set) == 0)
704 return 0;
705
706 if (trie_equal_v4(a->trie[0], b->trie[0]) == 0 ||
707 trie_equal_v4(a->trie[1], b->trie[1]) == 0)
708 return 0;
709
710 return 1;
711 }
712
713 static int
trie_equal_v6(struct tentry_v6 * a,struct tentry_v6 * b)714 trie_equal_v6(struct tentry_v6 *a, struct tentry_v6 *b)
715 {
716 if (a == NULL && b == NULL)
717 return 1;
718 if (a == NULL || b == NULL)
719 return 0;
720
721 if (memcmp(&a->addr, &b->addr, sizeof(a->addr)) != 0 ||
722 a->plen != b->plen ||
723 a->node != b->node ||
724 memcmp(&a->plenmask, &b->plenmask, sizeof(a->plenmask)) != 0)
725 return 0;
726
727 if (set_equal(a->set, b->set) == 0)
728 return 0;
729
730 if (trie_equal_v6(a->trie[0], b->trie[0]) == 0 ||
731 trie_equal_v6(a->trie[1], b->trie[1]) == 0)
732 return 0;
733
734 return 1;
735 }
736
737 /* Compare two tries and return 1 if they are the same else 0. */
738 int
trie_equal(struct trie_head * a,struct trie_head * b)739 trie_equal(struct trie_head *a, struct trie_head *b)
740 {
741 if (a->match_default_v4 != b->match_default_v4 ||
742 a->match_default_v6 != b->match_default_v6)
743 return 0;
744 if (trie_equal_v4(a->root_v4, b->root_v4) == 0)
745 return 0;
746 if (trie_equal_v6(a->root_v6, b->root_v6) == 0)
747 return 0;
748 return 1;
749 }
750
751 /* debugging functions for printing the trie */
752 static void
trie_dump_v4(struct tentry_v4 * n)753 trie_dump_v4(struct tentry_v4 *n)
754 {
755 if (n == NULL)
756 return;
757 if (n->node)
758 fprintf(stderr, "%s/%u plenmask %08x\n", inet_ntoa(n->addr),
759 n->plen, n->plenmask.s_addr);
760 else
761 fprintf(stderr, " %s/%u\n", inet_ntoa(n->addr), n->plen);
762
763 trie_dump_v4(n->trie[0]);
764 trie_dump_v4(n->trie[1]);
765 }
766
767 static void
trie_dump_v6(struct tentry_v6 * n)768 trie_dump_v6(struct tentry_v6 *n)
769 {
770 char buf[48];
771 unsigned int i;
772
773 if (n == NULL)
774 return;
775 if (n->node) {
776 fprintf(stderr, "%s/%u plenmask ",
777 inet_ntop(AF_INET6, &n->addr, buf, sizeof(buf)), n->plen);
778 for (i = 0; i < sizeof(n->plenmask); i++)
779 fprintf(stderr, "%02x", n->plenmask.s6_addr[i]);
780 fprintf(stderr, "\n");
781 } else
782 fprintf(stderr, " %s/%u\n",
783 inet_ntop(AF_INET6, &n->addr, buf, sizeof(buf)), n->plen);
784
785 trie_dump_v6(n->trie[0]);
786 trie_dump_v6(n->trie[1]);
787 }
788
789 void
trie_dump(struct trie_head * th)790 trie_dump(struct trie_head *th)
791 {
792 if (th->match_default_v4)
793 fprintf(stderr, "0.0.0.0/0 plenmask 0\n");
794 trie_dump_v4(th->root_v4);
795 if (th->match_default_v6)
796 fprintf(stderr, "::/0 plenmask 0\n");
797 trie_dump_v6(th->root_v6);
798 }
799