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