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 * 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->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 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 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 * 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 139 flowspec_free(struct flowspec_config *f) 140 { 141 filterset_free(&f->attrset); 142 free(f->flow); 143 free(f); 144 } 145 146 void 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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