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