xref: /openbsd/usr.sbin/bgpd/rde_trie.c (revision 3a50f0a9)
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