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