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