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