xref: /openbsd/usr.sbin/bgpd/config.c (revision 3bef86f7)
1 /*	$OpenBSD: config.c,v 1.108 2023/08/16 08:26:35 claudio Exp $ */
2 
3 /*
4  * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@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 
19 #include <sys/types.h>
20 #include <sys/socket.h>
21 
22 #include <errno.h>
23 #include <ifaddrs.h>
24 #include <netdb.h>
25 #include <stddef.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "bgpd.h"
32 #include "session.h"
33 #include "log.h"
34 
35 int		host_ip(const char *, struct bgpd_addr *, uint8_t *);
36 void		free_networks(struct network_head *);
37 void		free_flowspecs(struct flowspec_tree *);
38 
39 struct bgpd_config *
40 new_config(void)
41 {
42 	struct bgpd_config	*conf;
43 
44 	if ((conf = calloc(1, sizeof(struct bgpd_config))) == NULL)
45 		fatal(NULL);
46 
47 	if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL)
48 		fatal(NULL);
49 	if ((conf->listen_addrs = calloc(1, sizeof(struct listen_addrs))) ==
50 	    NULL)
51 		fatal(NULL);
52 	if ((conf->mrt = calloc(1, sizeof(struct mrt_head))) == NULL)
53 		fatal(NULL);
54 
55 	/* init the various list for later */
56 	RB_INIT(&conf->peers);
57 	TAILQ_INIT(&conf->networks);
58 	RB_INIT(&conf->flowspecs);
59 	SIMPLEQ_INIT(&conf->l3vpns);
60 	SIMPLEQ_INIT(&conf->prefixsets);
61 	SIMPLEQ_INIT(&conf->originsets);
62 	SIMPLEQ_INIT(&conf->rde_prefixsets);
63 	SIMPLEQ_INIT(&conf->rde_originsets);
64 	RB_INIT(&conf->roa);
65 	RB_INIT(&conf->aspa);
66 	SIMPLEQ_INIT(&conf->as_sets);
67 	SIMPLEQ_INIT(&conf->rtrs);
68 
69 	TAILQ_INIT(conf->filters);
70 	TAILQ_INIT(conf->listen_addrs);
71 	LIST_INIT(conf->mrt);
72 
73 	return (conf);
74 }
75 
76 void
77 copy_config(struct bgpd_config *to, struct bgpd_config *from)
78 {
79 	to->flags = from->flags;
80 	to->log = from->log;
81 	to->default_tableid = from->default_tableid;
82 	to->bgpid = from->bgpid;
83 	to->clusterid = from->clusterid;
84 	to->as = from->as;
85 	to->short_as = from->short_as;
86 	to->holdtime = from->holdtime;
87 	to->min_holdtime = from->min_holdtime;
88 	to->connectretry = from->connectretry;
89 	to->fib_priority = from->fib_priority;
90 }
91 
92 void
93 network_free(struct network *n)
94 {
95 	rtlabel_unref(n->net.rtlabel);
96 	filterset_free(&n->net.attrset);
97 	free(n);
98 }
99 
100 void
101 free_networks(struct network_head *networks)
102 {
103 	struct network		*n;
104 
105 	while ((n = TAILQ_FIRST(networks)) != NULL) {
106 		TAILQ_REMOVE(networks, n, entry);
107 		network_free(n);
108 	}
109 }
110 
111 struct flowspec_config *
112 flowspec_alloc(uint8_t aid, int len)
113 {
114 	struct flowspec_config *conf;
115 	struct flowspec *flow;
116 
117 	flow = malloc(FLOWSPEC_SIZE + len);
118 	if (flow == NULL)
119 		return NULL;
120 	memset(flow, 0, FLOWSPEC_SIZE);
121 
122 	conf = calloc(1, sizeof(*conf));
123 	if (conf == NULL) {
124 		free(flow);
125 		return NULL;
126 	}
127 
128 	conf->flow = flow;
129 	TAILQ_INIT(&conf->attrset);
130 	flow->len = len;
131 	flow->aid = aid;
132 
133 	return conf;
134 }
135 
136 void
137 flowspec_free(struct flowspec_config *f)
138 {
139 	filterset_free(&f->attrset);
140 	free(f->flow);
141 	free(f);
142 }
143 
144 void
145 free_flowspecs(struct flowspec_tree *flowspecs)
146 {
147 	struct flowspec_config *f, *nf;
148 
149 	RB_FOREACH_SAFE(f, flowspec_tree, flowspecs, nf) {
150 		RB_REMOVE(flowspec_tree, flowspecs, f);
151 		flowspec_free(f);
152 	}
153 }
154 
155 void
156 free_l3vpns(struct l3vpn_head *l3vpns)
157 {
158 	struct l3vpn		*vpn;
159 
160 	while ((vpn = SIMPLEQ_FIRST(l3vpns)) != NULL) {
161 		SIMPLEQ_REMOVE_HEAD(l3vpns, entry);
162 		filterset_free(&vpn->export);
163 		filterset_free(&vpn->import);
164 		free_networks(&vpn->net_l);
165 		free(vpn);
166 	}
167 }
168 
169 void
170 free_prefixsets(struct prefixset_head *psh)
171 {
172 	struct prefixset	*ps;
173 
174 	while (!SIMPLEQ_EMPTY(psh)) {
175 		ps = SIMPLEQ_FIRST(psh);
176 		free_roatree(&ps->roaitems);
177 		free_prefixtree(&ps->psitems);
178 		SIMPLEQ_REMOVE_HEAD(psh, entry);
179 		free(ps);
180 	}
181 }
182 
183 void
184 free_rde_prefixsets(struct rde_prefixset_head *psh)
185 {
186 	struct rde_prefixset	*ps;
187 
188 	if (psh == NULL)
189 		return;
190 
191 	while (!SIMPLEQ_EMPTY(psh)) {
192 		ps = SIMPLEQ_FIRST(psh);
193 		trie_free(&ps->th);
194 		SIMPLEQ_REMOVE_HEAD(psh, entry);
195 		free(ps);
196 	}
197 }
198 
199 void
200 free_prefixtree(struct prefixset_tree *p)
201 {
202 	struct prefixset_item	*psi, *npsi;
203 
204 	RB_FOREACH_SAFE(psi, prefixset_tree, p, npsi) {
205 		RB_REMOVE(prefixset_tree, p, psi);
206 		free(psi);
207 	}
208 }
209 
210 void
211 free_roatree(struct roa_tree *r)
212 {
213 	struct roa	*roa, *nroa;
214 
215 	RB_FOREACH_SAFE(roa, roa_tree, r, nroa) {
216 		RB_REMOVE(roa_tree, r, roa);
217 		free(roa);
218 	}
219 }
220 
221 void
222 free_aspa(struct aspa_set *aspa)
223 {
224 	if (aspa == NULL)
225 		return;
226 	free(aspa->tas);
227 	free(aspa);
228 }
229 
230 void
231 free_aspatree(struct aspa_tree *a)
232 {
233 	struct aspa_set	*aspa, *naspa;
234 
235 	RB_FOREACH_SAFE(aspa, aspa_tree, a, naspa) {
236 		RB_REMOVE(aspa_tree, a, aspa);
237 		free_aspa(aspa);
238 	}
239 }
240 
241 void
242 free_rtrs(struct rtr_config_head *rh)
243 {
244 	struct rtr_config	*r;
245 
246 	while (!SIMPLEQ_EMPTY(rh)) {
247 		r = SIMPLEQ_FIRST(rh);
248 		SIMPLEQ_REMOVE_HEAD(rh, entry);
249 		free(r);
250 	}
251 }
252 
253 void
254 free_config(struct bgpd_config *conf)
255 {
256 	struct peer		*p, *next;
257 	struct listen_addr	*la;
258 	struct mrt		*m;
259 
260 	free_l3vpns(&conf->l3vpns);
261 	free_networks(&conf->networks);
262 	free_flowspecs(&conf->flowspecs);
263 	filterlist_free(conf->filters);
264 	free_prefixsets(&conf->prefixsets);
265 	free_prefixsets(&conf->originsets);
266 	free_rde_prefixsets(&conf->rde_prefixsets);
267 	free_rde_prefixsets(&conf->rde_originsets);
268 	as_sets_free(&conf->as_sets);
269 	free_roatree(&conf->roa);
270 	free_aspatree(&conf->aspa);
271 	free_rtrs(&conf->rtrs);
272 
273 	while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
274 		TAILQ_REMOVE(conf->listen_addrs, la, entry);
275 		free(la);
276 	}
277 	free(conf->listen_addrs);
278 
279 	while ((m = LIST_FIRST(conf->mrt)) != NULL) {
280 		LIST_REMOVE(m, entry);
281 		free(m);
282 	}
283 	free(conf->mrt);
284 
285 	RB_FOREACH_SAFE(p, peer_head, &conf->peers, next) {
286 		RB_REMOVE(peer_head, &conf->peers, p);
287 		free(p);
288 	}
289 
290 	free(conf->csock);
291 	free(conf->rcsock);
292 
293 	free(conf);
294 }
295 
296 void
297 merge_config(struct bgpd_config *xconf, struct bgpd_config *conf)
298 {
299 	struct listen_addr	*nla, *ola, *next;
300 	struct peer		*p, *np, *nextp;
301 	struct flowspec_config	*f, *nextf, *xf;
302 
303 	/*
304 	 * merge the freshly parsed conf into the running xconf
305 	 */
306 
307 	/* adjust FIB priority if changed */
308 	/* if xconf is uninitialized we get RTP_NONE */
309 	if (xconf->fib_priority != conf->fib_priority) {
310 		kr_fib_decouple_all();
311 		kr_fib_prio_set(conf->fib_priority);
312 		kr_fib_couple_all();
313 	}
314 
315 	/* take over the easy config changes */
316 	copy_config(xconf, conf);
317 
318 	/* clear old control sockets and use new */
319 	free(xconf->csock);
320 	free(xconf->rcsock);
321 	xconf->csock = conf->csock;
322 	xconf->rcsock = conf->rcsock;
323 	/* set old one to NULL so we don't double free */
324 	conf->csock = NULL;
325 	conf->rcsock = NULL;
326 
327 	/* clear all current filters and take over the new ones */
328 	filterlist_free(xconf->filters);
329 	xconf->filters = conf->filters;
330 	conf->filters = NULL;
331 
332 	/* merge mrt config */
333 	mrt_mergeconfig(xconf->mrt, conf->mrt);
334 
335 	/* switch the roa, first remove the old one */
336 	free_roatree(&xconf->roa);
337 	/* then move the RB tree root */
338 	RB_ROOT(&xconf->roa) = RB_ROOT(&conf->roa);
339 	RB_ROOT(&conf->roa) = NULL;
340 
341 	/* switch the aspa, first remove the old one */
342 	free_aspatree(&xconf->aspa);
343 	/* then move the RB tree root */
344 	RB_ROOT(&xconf->aspa) = RB_ROOT(&conf->aspa);
345 	RB_ROOT(&conf->aspa) = NULL;
346 
347 	/* switch the rtr_configs, first remove the old ones */
348 	free_rtrs(&xconf->rtrs);
349 	SIMPLEQ_CONCAT(&xconf->rtrs, &conf->rtrs);
350 
351 	/* switch the prefixsets, first remove the old ones */
352 	free_prefixsets(&xconf->prefixsets);
353 	SIMPLEQ_CONCAT(&xconf->prefixsets, &conf->prefixsets);
354 
355 	/* switch the originsets, first remove the old ones */
356 	free_prefixsets(&xconf->originsets);
357 	SIMPLEQ_CONCAT(&xconf->originsets, &conf->originsets);
358 
359 	/* switch the as_sets, first remove the old ones */
360 	as_sets_free(&xconf->as_sets);
361 	SIMPLEQ_CONCAT(&xconf->as_sets, &conf->as_sets);
362 
363 	/* switch the network statements, but first remove the old ones */
364 	free_networks(&xconf->networks);
365 	TAILQ_CONCAT(&xconf->networks, &conf->networks, entry);
366 
367 	/*
368 	 * Merge the flowspec statements. Mark the old ones for deletion
369 	 * which happens when the flowspec is sent to the RDE.
370 	 */
371 	RB_FOREACH(f, flowspec_tree, &xconf->flowspecs)
372 		f->reconf_action = RECONF_DELETE;
373 
374 	RB_FOREACH_SAFE(f, flowspec_tree, &conf->flowspecs, nextf) {
375 		RB_REMOVE(flowspec_tree, &conf->flowspecs, f);
376 
377 		xf = RB_INSERT(flowspec_tree, &xconf->flowspecs, f);
378 		if (xf != NULL) {
379 			filterset_free(&xf->attrset);
380 			filterset_move(&f->attrset, &xf->attrset);
381 			flowspec_free(f);
382 			xf->reconf_action = RECONF_KEEP;
383 		} else
384 			f->reconf_action = RECONF_KEEP;
385 	}
386 
387 	/* switch the l3vpn configs, first remove the old ones */
388 	free_l3vpns(&xconf->l3vpns);
389 	SIMPLEQ_CONCAT(&xconf->l3vpns, &conf->l3vpns);
390 
391 	/*
392 	 * merge new listeners:
393 	 * -flag all existing ones as to be deleted
394 	 * -those that are in both new and old: flag to keep
395 	 * -new ones get inserted and flagged as to reinit
396 	 * -remove all that are still flagged for deletion
397 	 */
398 
399 	TAILQ_FOREACH(nla, xconf->listen_addrs, entry)
400 		nla->reconf = RECONF_DELETE;
401 
402 	/* no new listeners? preserve default ones */
403 	if (TAILQ_EMPTY(conf->listen_addrs))
404 		TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
405 			if (ola->flags & DEFAULT_LISTENER)
406 				ola->reconf = RECONF_KEEP;
407 	/* else loop over listeners and merge configs */
408 	for (nla = TAILQ_FIRST(conf->listen_addrs); nla != NULL; nla = next) {
409 		next = TAILQ_NEXT(nla, entry);
410 
411 		TAILQ_FOREACH(ola, xconf->listen_addrs, entry)
412 			if (!memcmp(&nla->sa, &ola->sa, sizeof(nla->sa)))
413 				break;
414 
415 		if (ola == NULL) {
416 			/* new listener, copy over */
417 			TAILQ_REMOVE(conf->listen_addrs, nla, entry);
418 			TAILQ_INSERT_TAIL(xconf->listen_addrs, nla, entry);
419 			nla->reconf = RECONF_REINIT;
420 		} else		/* exists, just flag */
421 			ola->reconf = RECONF_KEEP;
422 	}
423 	/* finally clean up the original list and remove all stale entries */
424 	for (nla = TAILQ_FIRST(xconf->listen_addrs); nla != NULL; nla = next) {
425 		next = TAILQ_NEXT(nla, entry);
426 		if (nla->reconf == RECONF_DELETE) {
427 			TAILQ_REMOVE(xconf->listen_addrs, nla, entry);
428 			free(nla);
429 		}
430 	}
431 
432 	/*
433 	 * merge peers:
434 	 * - need to know which peers are new, replaced and removed
435 	 * - walk over old peers and check if there is a corresponding new
436 	 *   peer if so mark it RECONF_KEEP. Remove all old peers.
437 	 * - swap lists (old peer list is actually empty).
438 	 */
439 	RB_FOREACH_SAFE(p, peer_head, &xconf->peers, nextp) {
440 		np = getpeerbyid(conf, p->conf.id);
441 		if (np != NULL) {
442 			np->reconf_action = RECONF_KEEP;
443 			/* copy the auth state since parent uses it */
444 			np->auth = p->auth;
445 		} else {
446 			/* peer no longer exists, clear pfkey state */
447 			pfkey_remove(p);
448 		}
449 
450 		RB_REMOVE(peer_head, &xconf->peers, p);
451 		free(p);
452 	}
453 	RB_FOREACH_SAFE(np, peer_head, &conf->peers, nextp) {
454 		RB_REMOVE(peer_head, &conf->peers, np);
455 		if (RB_INSERT(peer_head, &xconf->peers, np) != NULL)
456 			fatalx("%s: peer tree is corrupt", __func__);
457 	}
458 
459 	/* conf is merged so free it */
460 	free_config(conf);
461 }
462 
463 uint32_t
464 get_bgpid(void)
465 {
466 	struct ifaddrs		*ifap, *ifa;
467 	uint32_t		 ip = 0, cur, localnet;
468 
469 	localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET);
470 
471 	if (getifaddrs(&ifap) == -1)
472 		fatal("getifaddrs");
473 
474 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
475 		if (ifa->ifa_addr == NULL ||
476 		    ifa->ifa_addr->sa_family != AF_INET)
477 			continue;
478 		cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
479 		if ((cur & localnet) == localnet)	/* skip 127/8 */
480 			continue;
481 		if (ntohl(cur) > ntohl(ip))
482 			ip = cur;
483 	}
484 	freeifaddrs(ifap);
485 
486 	return (ip);
487 }
488 
489 int
490 host(const char *s, struct bgpd_addr *h, uint8_t *len)
491 {
492 	int			 mask = 128;
493 	char			*p, *ps;
494 	const char		*errstr;
495 
496 	if ((ps = strdup(s)) == NULL)
497 		fatal("%s: strdup", __func__);
498 
499 	if ((p = strrchr(ps, '/')) != NULL) {
500 		mask = strtonum(p+1, 0, 128, &errstr);
501 		if (errstr) {
502 			log_warnx("prefixlen is %s: %s", errstr, p);
503 			free(ps);
504 			return (0);
505 		}
506 		p[0] = '\0';
507 	}
508 
509 	memset(h, 0, sizeof(*h));
510 
511 	if (host_ip(ps, h, len) == 0) {
512 		free(ps);
513 		return (0);
514 	}
515 
516 	if (p != NULL)
517 		*len = mask;
518 
519 	free(ps);
520 	return (1);
521 }
522 
523 int
524 host_ip(const char *s, struct bgpd_addr *h, uint8_t *len)
525 {
526 	struct addrinfo		 hints, *res;
527 	int			 bits;
528 
529 	memset(&hints, 0, sizeof(hints));
530 	hints.ai_family = AF_UNSPEC;
531 	hints.ai_socktype = SOCK_DGRAM; /*dummy*/
532 	hints.ai_flags = AI_NUMERICHOST;
533 	if (getaddrinfo(s, NULL, &hints, &res) == 0) {
534 		*len = res->ai_family == AF_INET6 ? 128 : 32;
535 		sa2addr(res->ai_addr, h, NULL);
536 		freeaddrinfo(res);
537 	} else {	/* ie. for 10/8 parsing */
538 		if ((bits = inet_net_pton(AF_INET, s, &h->v4,
539 		    sizeof(h->v4))) == -1)
540 			return (0);
541 		*len = bits;
542 		h->aid = AID_INET;
543 	}
544 
545 	return (1);
546 }
547 
548 int
549 prepare_listeners(struct bgpd_config *conf)
550 {
551 	struct listen_addr	*la, *next;
552 	int			 opt = 1;
553 	int			 r = 0;
554 
555 	for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) {
556 		next = TAILQ_NEXT(la, entry);
557 		if (la->reconf != RECONF_REINIT)
558 			continue;
559 
560 		if ((la->fd = socket(la->sa.ss_family,
561 		    SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
562 		    IPPROTO_TCP)) == -1) {
563 			if (la->flags & DEFAULT_LISTENER && (errno ==
564 			    EAFNOSUPPORT || errno == EPROTONOSUPPORT)) {
565 				TAILQ_REMOVE(conf->listen_addrs, la, entry);
566 				free(la);
567 				continue;
568 			} else
569 				fatal("socket");
570 		}
571 
572 		opt = 1;
573 		if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR,
574 		    &opt, sizeof(opt)) == -1)
575 			fatal("setsockopt SO_REUSEADDR");
576 
577 		if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa_len) ==
578 		    -1) {
579 			switch (la->sa.ss_family) {
580 			case AF_INET:
581 				log_warn("cannot bind to %s:%u",
582 				    log_sockaddr((struct sockaddr *)&la->sa,
583 				    la->sa_len), ntohs(((struct sockaddr_in *)
584 				    &la->sa)->sin_port));
585 				break;
586 			case AF_INET6:
587 				log_warn("cannot bind to [%s]:%u",
588 				    log_sockaddr((struct sockaddr *)&la->sa,
589 				    la->sa_len), ntohs(((struct sockaddr_in6 *)
590 				    &la->sa)->sin6_port));
591 				break;
592 			default:
593 				log_warn("cannot bind to %s",
594 				    log_sockaddr((struct sockaddr *)&la->sa,
595 				    la->sa_len));
596 				break;
597 			}
598 			close(la->fd);
599 			TAILQ_REMOVE(conf->listen_addrs, la, entry);
600 			free(la);
601 			r = -1;
602 			continue;
603 		}
604 	}
605 
606 	return (r);
607 }
608 
609 void
610 expand_networks(struct bgpd_config *c, struct network_head *nw)
611 {
612 	struct network		*n, *m, *tmp;
613 	struct prefixset	*ps;
614 	struct prefixset_item	*psi;
615 
616 	TAILQ_FOREACH_SAFE(n, nw, entry, tmp) {
617 		if (n->net.type == NETWORK_PREFIXSET) {
618 			TAILQ_REMOVE(nw, n, entry);
619 			if ((ps = find_prefixset(n->net.psname, &c->prefixsets))
620 			    == NULL)
621 				fatal("%s: prefixset %s not found", __func__,
622 				    n->net.psname);
623 			RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
624 				if ((m = calloc(1, sizeof(struct network)))
625 				    == NULL)
626 					fatal(NULL);
627 				memcpy(&m->net.prefix, &psi->p.addr,
628 				    sizeof(m->net.prefix));
629 				m->net.prefixlen = psi->p.len;
630 				filterset_copy(&n->net.attrset,
631 				    &m->net.attrset);
632 				TAILQ_INSERT_TAIL(nw, m, entry);
633 			}
634 			network_free(n);
635 		}
636 	}
637 }
638 
639 static inline int
640 prefixset_cmp(struct prefixset_item *a, struct prefixset_item *b)
641 {
642 	int i;
643 
644 	if (a->p.addr.aid < b->p.addr.aid)
645 		return (-1);
646 	if (a->p.addr.aid > b->p.addr.aid)
647 		return (1);
648 
649 	switch (a->p.addr.aid) {
650 	case AID_INET:
651 		i = memcmp(&a->p.addr.v4, &b->p.addr.v4,
652 		    sizeof(struct in_addr));
653 		break;
654 	case AID_INET6:
655 		i = memcmp(&a->p.addr.v6, &b->p.addr.v6,
656 		    sizeof(struct in6_addr));
657 		break;
658 	default:
659 		fatalx("%s: unknown af", __func__);
660 	}
661 	if (i > 0)
662 		return (1);
663 	if (i < 0)
664 		return (-1);
665 	if (a->p.len < b->p.len)
666 		return (-1);
667 	if (a->p.len > b->p.len)
668 		return (1);
669 	if (a->p.len_min < b->p.len_min)
670 		return (-1);
671 	if (a->p.len_min > b->p.len_min)
672 		return (1);
673 	if (a->p.len_max < b->p.len_max)
674 		return (-1);
675 	if (a->p.len_max > b->p.len_max)
676 		return (1);
677 	return (0);
678 }
679 
680 RB_GENERATE(prefixset_tree, prefixset_item, entry, prefixset_cmp);
681 
682 static inline int
683 roa_cmp(struct roa *a, struct roa *b)
684 {
685 	int i;
686 
687 	if (a->aid < b->aid)
688 		return (-1);
689 	if (a->aid > b->aid)
690 		return (1);
691 
692 	switch (a->aid) {
693 	case AID_INET:
694 		i = memcmp(&a->prefix.inet, &b->prefix.inet,
695 		    sizeof(struct in_addr));
696 		break;
697 	case AID_INET6:
698 		i = memcmp(&a->prefix.inet6, &b->prefix.inet6,
699 		    sizeof(struct in6_addr));
700 		break;
701 	default:
702 		fatalx("%s: unknown af", __func__);
703 	}
704 	if (i > 0)
705 		return (1);
706 	if (i < 0)
707 		return (-1);
708 	if (a->prefixlen < b->prefixlen)
709 		return (-1);
710 	if (a->prefixlen > b->prefixlen)
711 		return (1);
712 
713 	if (a->asnum < b->asnum)
714 		return (-1);
715 	if (a->asnum > b->asnum)
716 		return (1);
717 
718 	if (a->maxlen < b->maxlen)
719 		return (-1);
720 	if (a->maxlen > b->maxlen)
721 		return (1);
722 
723 	return (0);
724 }
725 
726 RB_GENERATE(roa_tree, roa, entry, roa_cmp);
727 
728 static inline int
729 aspa_cmp(struct aspa_set *a, struct aspa_set *b)
730 {
731 	if (a->as < b->as)
732 		return (-1);
733 	if (a->as > b->as)
734 		return (1);
735 	return (0);
736 }
737 
738 RB_GENERATE(aspa_tree, aspa_set, entry, aspa_cmp);
739 
740 static inline int
741 flowspec_config_cmp(struct flowspec_config *a, struct flowspec_config *b)
742 {
743 	if (a->flow->aid < b->flow->aid)
744 		return -1;
745 	if (a->flow->aid > b->flow->aid)
746 		return 1;
747 
748 	return flowspec_cmp(a->flow->data, a->flow->len,
749 	    b->flow->data, b->flow->len, a->flow->aid == AID_FLOWSPECv6);
750 }
751 
752 RB_GENERATE(flowspec_tree, flowspec_config, entry, flowspec_config_cmp);
753