1 /* $OpenBSD: config.c,v 1.107 2023/04/18 12:11:27 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 * 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 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 } 91 92 void 93 network_free(struct network *n) 94 { 95 rtlabel_unref(n->net.rtlabel); 96 filterset_free(&n->net.attrset); 97 free(n); 98 } 99 100 void 101 free_networks(struct network_head *networks) 102 { 103 struct network *n; 104 105 while ((n = TAILQ_FIRST(networks)) != NULL) { 106 TAILQ_REMOVE(networks, n, entry); 107 network_free(n); 108 } 109 } 110 111 struct flowspec_config * 112 flowspec_alloc(uint8_t aid, int len) 113 { 114 struct flowspec_config *conf; 115 struct flowspec *flow; 116 117 flow = malloc(FLOWSPEC_SIZE + len); 118 if (flow == NULL) 119 return NULL; 120 memset(flow, 0, FLOWSPEC_SIZE); 121 122 conf = calloc(1, sizeof(*conf)); 123 if (conf == NULL) { 124 free(flow); 125 return NULL; 126 } 127 128 conf->flow = flow; 129 TAILQ_INIT(&conf->attrset); 130 flow->len = len; 131 flow->aid = aid; 132 133 return conf; 134 } 135 136 void 137 flowspec_free(struct flowspec_config *f) 138 { 139 filterset_free(&f->attrset); 140 free(f->flow); 141 free(f); 142 } 143 144 void 145 free_flowspecs(struct flowspec_tree *flowspecs) 146 { 147 struct flowspec_config *f, *nf; 148 149 RB_FOREACH_SAFE(f, flowspec_tree, flowspecs, nf) { 150 RB_REMOVE(flowspec_tree, flowspecs, f); 151 flowspec_free(f); 152 } 153 } 154 155 void 156 free_l3vpns(struct l3vpn_head *l3vpns) 157 { 158 struct l3vpn *vpn; 159 160 while ((vpn = SIMPLEQ_FIRST(l3vpns)) != NULL) { 161 SIMPLEQ_REMOVE_HEAD(l3vpns, entry); 162 filterset_free(&vpn->export); 163 filterset_free(&vpn->import); 164 free_networks(&vpn->net_l); 165 free(vpn); 166 } 167 } 168 169 void 170 free_prefixsets(struct prefixset_head *psh) 171 { 172 struct prefixset *ps; 173 174 while (!SIMPLEQ_EMPTY(psh)) { 175 ps = SIMPLEQ_FIRST(psh); 176 free_roatree(&ps->roaitems); 177 free_prefixtree(&ps->psitems); 178 SIMPLEQ_REMOVE_HEAD(psh, entry); 179 free(ps); 180 } 181 } 182 183 void 184 free_rde_prefixsets(struct rde_prefixset_head *psh) 185 { 186 struct rde_prefixset *ps; 187 188 if (psh == NULL) 189 return; 190 191 while (!SIMPLEQ_EMPTY(psh)) { 192 ps = SIMPLEQ_FIRST(psh); 193 trie_free(&ps->th); 194 SIMPLEQ_REMOVE_HEAD(psh, entry); 195 free(ps); 196 } 197 } 198 199 void 200 free_prefixtree(struct prefixset_tree *p) 201 { 202 struct prefixset_item *psi, *npsi; 203 204 RB_FOREACH_SAFE(psi, prefixset_tree, p, npsi) { 205 RB_REMOVE(prefixset_tree, p, psi); 206 free(psi); 207 } 208 } 209 210 void 211 free_roatree(struct roa_tree *r) 212 { 213 struct roa *roa, *nroa; 214 215 RB_FOREACH_SAFE(roa, roa_tree, r, nroa) { 216 RB_REMOVE(roa_tree, r, roa); 217 free(roa); 218 } 219 } 220 221 void 222 free_aspa(struct aspa_set *aspa) 223 { 224 if (aspa == NULL) 225 return; 226 free(aspa->tas); 227 free(aspa->tas_aid); 228 free(aspa); 229 } 230 231 void 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 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 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 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. Remove all old peers. 438 * - swap lists (old peer list is actually empty). 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 /* copy the auth state since parent uses it */ 445 np->auth = p->auth; 446 } else { 447 /* peer no longer exists, clear pfkey state */ 448 pfkey_remove(p); 449 } 450 451 RB_REMOVE(peer_head, &xconf->peers, p); 452 free(p); 453 } 454 RB_FOREACH_SAFE(np, peer_head, &conf->peers, nextp) { 455 RB_REMOVE(peer_head, &conf->peers, np); 456 if (RB_INSERT(peer_head, &xconf->peers, np) != NULL) 457 fatalx("%s: peer tree is corrupt", __func__); 458 } 459 460 /* conf is merged so free it */ 461 free_config(conf); 462 } 463 464 uint32_t 465 get_bgpid(void) 466 { 467 struct ifaddrs *ifap, *ifa; 468 uint32_t ip = 0, cur, localnet; 469 470 localnet = htonl(INADDR_LOOPBACK & IN_CLASSA_NET); 471 472 if (getifaddrs(&ifap) == -1) 473 fatal("getifaddrs"); 474 475 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 476 if (ifa->ifa_addr == NULL || 477 ifa->ifa_addr->sa_family != AF_INET) 478 continue; 479 cur = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; 480 if ((cur & localnet) == localnet) /* skip 127/8 */ 481 continue; 482 if (ntohl(cur) > ntohl(ip)) 483 ip = cur; 484 } 485 freeifaddrs(ifap); 486 487 return (ip); 488 } 489 490 int 491 host(const char *s, struct bgpd_addr *h, uint8_t *len) 492 { 493 int mask = 128; 494 char *p, *ps; 495 const char *errstr; 496 497 if ((ps = strdup(s)) == NULL) 498 fatal("%s: strdup", __func__); 499 500 if ((p = strrchr(ps, '/')) != NULL) { 501 mask = strtonum(p+1, 0, 128, &errstr); 502 if (errstr) { 503 log_warnx("prefixlen is %s: %s", errstr, p); 504 free(ps); 505 return (0); 506 } 507 p[0] = '\0'; 508 } 509 510 memset(h, 0, sizeof(*h)); 511 512 if (host_ip(ps, h, len) == 0) { 513 free(ps); 514 return (0); 515 } 516 517 if (p != NULL) 518 *len = mask; 519 520 free(ps); 521 return (1); 522 } 523 524 int 525 host_ip(const char *s, struct bgpd_addr *h, uint8_t *len) 526 { 527 struct addrinfo hints, *res; 528 int bits; 529 530 memset(&hints, 0, sizeof(hints)); 531 hints.ai_family = AF_UNSPEC; 532 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 533 hints.ai_flags = AI_NUMERICHOST; 534 if (getaddrinfo(s, NULL, &hints, &res) == 0) { 535 *len = res->ai_family == AF_INET6 ? 128 : 32; 536 sa2addr(res->ai_addr, h, NULL); 537 freeaddrinfo(res); 538 } else { /* ie. for 10/8 parsing */ 539 if ((bits = inet_net_pton(AF_INET, s, &h->v4, 540 sizeof(h->v4))) == -1) 541 return (0); 542 *len = bits; 543 h->aid = AID_INET; 544 } 545 546 return (1); 547 } 548 549 int 550 prepare_listeners(struct bgpd_config *conf) 551 { 552 struct listen_addr *la, *next; 553 int opt = 1; 554 int r = 0; 555 556 for (la = TAILQ_FIRST(conf->listen_addrs); la != NULL; la = next) { 557 next = TAILQ_NEXT(la, entry); 558 if (la->reconf != RECONF_REINIT) 559 continue; 560 561 if ((la->fd = socket(la->sa.ss_family, 562 SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 563 IPPROTO_TCP)) == -1) { 564 if (la->flags & DEFAULT_LISTENER && (errno == 565 EAFNOSUPPORT || errno == EPROTONOSUPPORT)) { 566 TAILQ_REMOVE(conf->listen_addrs, la, entry); 567 free(la); 568 continue; 569 } else 570 fatal("socket"); 571 } 572 573 opt = 1; 574 if (setsockopt(la->fd, SOL_SOCKET, SO_REUSEADDR, 575 &opt, sizeof(opt)) == -1) 576 fatal("setsockopt SO_REUSEADDR"); 577 578 if (bind(la->fd, (struct sockaddr *)&la->sa, la->sa_len) == 579 -1) { 580 switch (la->sa.ss_family) { 581 case AF_INET: 582 log_warn("cannot bind to %s:%u", 583 log_sockaddr((struct sockaddr *)&la->sa, 584 la->sa_len), ntohs(((struct sockaddr_in *) 585 &la->sa)->sin_port)); 586 break; 587 case AF_INET6: 588 log_warn("cannot bind to [%s]:%u", 589 log_sockaddr((struct sockaddr *)&la->sa, 590 la->sa_len), ntohs(((struct sockaddr_in6 *) 591 &la->sa)->sin6_port)); 592 break; 593 default: 594 log_warn("cannot bind to %s", 595 log_sockaddr((struct sockaddr *)&la->sa, 596 la->sa_len)); 597 break; 598 } 599 close(la->fd); 600 TAILQ_REMOVE(conf->listen_addrs, la, entry); 601 free(la); 602 r = -1; 603 continue; 604 } 605 } 606 607 return (r); 608 } 609 610 void 611 expand_networks(struct bgpd_config *c, struct network_head *nw) 612 { 613 struct network *n, *m, *tmp; 614 struct prefixset *ps; 615 struct prefixset_item *psi; 616 617 TAILQ_FOREACH_SAFE(n, nw, entry, tmp) { 618 if (n->net.type == NETWORK_PREFIXSET) { 619 TAILQ_REMOVE(nw, n, entry); 620 if ((ps = find_prefixset(n->net.psname, &c->prefixsets)) 621 == NULL) 622 fatal("%s: prefixset %s not found", __func__, 623 n->net.psname); 624 RB_FOREACH(psi, prefixset_tree, &ps->psitems) { 625 if ((m = calloc(1, sizeof(struct network))) 626 == NULL) 627 fatal(NULL); 628 memcpy(&m->net.prefix, &psi->p.addr, 629 sizeof(m->net.prefix)); 630 m->net.prefixlen = psi->p.len; 631 filterset_copy(&n->net.attrset, 632 &m->net.attrset); 633 TAILQ_INSERT_TAIL(nw, m, entry); 634 } 635 network_free(n); 636 } 637 } 638 } 639 640 static inline int 641 prefixset_cmp(struct prefixset_item *a, struct prefixset_item *b) 642 { 643 int i; 644 645 if (a->p.addr.aid < b->p.addr.aid) 646 return (-1); 647 if (a->p.addr.aid > b->p.addr.aid) 648 return (1); 649 650 switch (a->p.addr.aid) { 651 case AID_INET: 652 i = memcmp(&a->p.addr.v4, &b->p.addr.v4, 653 sizeof(struct in_addr)); 654 break; 655 case AID_INET6: 656 i = memcmp(&a->p.addr.v6, &b->p.addr.v6, 657 sizeof(struct in6_addr)); 658 break; 659 default: 660 fatalx("%s: unknown af", __func__); 661 } 662 if (i > 0) 663 return (1); 664 if (i < 0) 665 return (-1); 666 if (a->p.len < b->p.len) 667 return (-1); 668 if (a->p.len > b->p.len) 669 return (1); 670 if (a->p.len_min < b->p.len_min) 671 return (-1); 672 if (a->p.len_min > b->p.len_min) 673 return (1); 674 if (a->p.len_max < b->p.len_max) 675 return (-1); 676 if (a->p.len_max > b->p.len_max) 677 return (1); 678 return (0); 679 } 680 681 RB_GENERATE(prefixset_tree, prefixset_item, entry, prefixset_cmp); 682 683 static inline int 684 roa_cmp(struct roa *a, struct roa *b) 685 { 686 int i; 687 688 if (a->aid < b->aid) 689 return (-1); 690 if (a->aid > b->aid) 691 return (1); 692 693 switch (a->aid) { 694 case AID_INET: 695 i = memcmp(&a->prefix.inet, &b->prefix.inet, 696 sizeof(struct in_addr)); 697 break; 698 case AID_INET6: 699 i = memcmp(&a->prefix.inet6, &b->prefix.inet6, 700 sizeof(struct in6_addr)); 701 break; 702 default: 703 fatalx("%s: unknown af", __func__); 704 } 705 if (i > 0) 706 return (1); 707 if (i < 0) 708 return (-1); 709 if (a->prefixlen < b->prefixlen) 710 return (-1); 711 if (a->prefixlen > b->prefixlen) 712 return (1); 713 714 if (a->asnum < b->asnum) 715 return (-1); 716 if (a->asnum > b->asnum) 717 return (1); 718 719 if (a->maxlen < b->maxlen) 720 return (-1); 721 if (a->maxlen > b->maxlen) 722 return (1); 723 724 return (0); 725 } 726 727 RB_GENERATE(roa_tree, roa, entry, roa_cmp); 728 729 static inline int 730 aspa_cmp(struct aspa_set *a, struct aspa_set *b) 731 { 732 if (a->as < b->as) 733 return (-1); 734 if (a->as > b->as) 735 return (1); 736 return (0); 737 } 738 739 RB_GENERATE(aspa_tree, aspa_set, entry, aspa_cmp); 740 741 static inline int 742 flowspec_config_cmp(struct flowspec_config *a, struct flowspec_config *b) 743 { 744 if (a->flow->aid < b->flow->aid) 745 return -1; 746 if (a->flow->aid > b->flow->aid) 747 return 1; 748 749 return flowspec_cmp(a->flow->data, a->flow->len, 750 b->flow->data, b->flow->len, a->flow->aid == AID_FLOWSPECv6); 751 } 752 753 RB_GENERATE(flowspec_tree, flowspec_config, entry, flowspec_config_cmp); 754