From: claudio Date: Fri, 18 Nov 2022 10:17:23 +0000 (+0000) Subject: Add plumbing for ASPA support. This implements the parser and part of the X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ff84f55eb3764bd2683e8442ac588f66539c38f6;p=openbsd Add plumbing for ASPA support. This implements the parser and part of the logic in the rtr process. It does not implement the new RTR messages yet but it is possible to specify an aspa-set in the config. Also the validation code in the RDE is missing so this does not do anything. With this in it will be possible to extend rpki-client to publish an aspa-set as part of the openbgpd config file. OK tb@ --- diff --git a/usr.sbin/bgpd/bgpd.c b/usr.sbin/bgpd/bgpd.c index 8632d76ebec..c8778841bbb 100644 --- a/usr.sbin/bgpd/bgpd.c +++ b/usr.sbin/bgpd/bgpd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.c,v 1.254 2022/08/17 15:15:25 claudio Exp $ */ +/* $OpenBSD: bgpd.c,v 1.255 2022/11/18 10:17:23 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -594,7 +595,8 @@ send_config(struct bgpd_config *conf) struct as_set *aset; struct prefixset *ps; struct prefixset_item *psi, *npsi; - struct roa *roa, *nroa; + struct roa *roa; + struct aspa_set *aspa; struct rtr_config *rtr; reconfpending = 3; /* one per child */ @@ -676,24 +678,37 @@ send_config(struct bgpd_config *conf) if (imsg_compose(ibuf_rde, IMSG_RECONF_ORIGIN_SET, 0, 0, -1, ps->name, sizeof(ps->name)) == -1) return (-1); - RB_FOREACH_SAFE(roa, roa_tree, &ps->roaitems, nroa) { - RB_REMOVE(roa_tree, &ps->roaitems, roa); + RB_FOREACH(roa, roa_tree, &ps->roaitems) { if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_ITEM, 0, 0, -1, roa, sizeof(*roa)) == -1) return (-1); - free(roa); } + free_roatree(&ps->roaitems); free(ps); } - /* roa table and rtr config are sent to the RTR engine */ - RB_FOREACH_SAFE(roa, roa_tree, &conf->roa, nroa) { - RB_REMOVE(roa_tree, &conf->roa, roa); + /* roa table, aspa table and rtr config are sent to the RTR engine */ + RB_FOREACH(roa, roa_tree, &conf->roa) { if (imsg_compose(ibuf_rtr, IMSG_RECONF_ROA_ITEM, 0, 0, -1, roa, sizeof(*roa)) == -1) return (-1); - free(roa); } + free_roatree(&conf->roa); + RB_FOREACH(aspa, aspa_tree, &conf->aspa) { + if (imsg_compose(ibuf_rtr, IMSG_RECONF_ASPA, 0, 0, + -1, aspa, offsetof(struct aspa_set, tas)) == -1) + return (-1); + if (imsg_compose(ibuf_rtr, IMSG_RECONF_ASPA_TAS, 0, 0, + -1, aspa->tas, sizeof(*aspa->tas) * aspa->num) == -1) + return (-1); + if (imsg_compose(ibuf_rtr, IMSG_RECONF_ASPA_TAS_AID, + 0, 0, -1, aspa->tas_aid, aspa->num) == -1) + return (-1); + if (imsg_compose(ibuf_rtr, IMSG_RECONF_ASPA_DONE, 0, 0, -1, + NULL, 0) == -1) + return -1; + } + free_aspatree(&conf->aspa); SIMPLEQ_FOREACH(rtr, &conf->rtrs, entry) { if (imsg_compose(ibuf_rtr, IMSG_RECONF_RTR_CONFIG, rtr->id, 0, -1, rtr->descr, sizeof(rtr->descr)) == -1) diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 70d47382f69..75a8cc9e440 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.454 2022/09/23 15:50:41 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.455 2022/11/18 10:17:23 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -263,6 +263,7 @@ struct roa { }; RB_HEAD(roa_tree, roa); +RB_HEAD(aspa_tree, aspa_set); struct set_table; struct as_set; @@ -284,6 +285,7 @@ struct bgpd_config { struct prefixset_head prefixsets; struct prefixset_head originsets; struct roa_tree roa; + struct aspa_tree aspa; struct rde_prefixset_head rde_prefixsets; struct rde_prefixset_head rde_originsets; struct as_set_head as_sets; @@ -582,6 +584,10 @@ enum imsg_type { IMSG_RECONF_ORIGIN_SET, IMSG_RECONF_ROA_SET, IMSG_RECONF_ROA_ITEM, + IMSG_RECONF_ASPA, + IMSG_RECONF_ASPA_TAS, + IMSG_RECONF_ASPA_TAS_AID, + IMSG_RECONF_ASPA_DONE, IMSG_RECONF_RTR_CONFIG, IMSG_RECONF_DRAIN, IMSG_RECONF_DONE, @@ -1149,6 +1155,15 @@ struct as_set { int dirty; }; +struct aspa_set { + time_t expires; + uint32_t as; + uint32_t num; + uint32_t *tas; + uint8_t *tas_aid; + RB_ENTRY(aspa_set) entry; +}; + struct l3vpn { SIMPLEQ_ENTRY(l3vpn) entry; char descr[PEER_DESCR_LEN]; @@ -1270,14 +1285,16 @@ void free_prefixsets(struct prefixset_head *); void free_rde_prefixsets(struct rde_prefixset_head *); void free_prefixtree(struct prefixset_tree *); void free_roatree(struct roa_tree *); +void free_aspa(struct aspa_set *); +void free_aspatree(struct aspa_tree *); void free_rtrs(struct rtr_config_head *); void filterlist_free(struct filter_head *); int host(const char *, struct bgpd_addr *, uint8_t *); uint32_t get_bgpid(void); void expand_networks(struct bgpd_config *, struct network_head *); RB_PROTOTYPE(prefixset_tree, prefixset_item, entry, prefixset_cmp); -int roa_cmp(struct roa *, struct roa *); RB_PROTOTYPE(roa_tree, roa, entry, roa_cmp); +RB_PROTOTYPE(aspa_tree, aspa_set, entry, aspa_cmp); /* kroute.c */ int kr_init(int *, uint8_t); diff --git a/usr.sbin/bgpd/config.c b/usr.sbin/bgpd/config.c index d6f2163b750..28c0e83a2f3 100644 --- a/usr.sbin/bgpd/config.c +++ b/usr.sbin/bgpd/config.c @@ -1,4 +1,4 @@ -/* $OpenBSD: config.c,v 1.104 2022/08/17 15:15:25 claudio Exp $ */ +/* $OpenBSD: config.c,v 1.105 2022/11/18 10:17:23 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer @@ -59,6 +59,7 @@ new_config(void) SIMPLEQ_INIT(&conf->rde_prefixsets); SIMPLEQ_INIT(&conf->rde_originsets); RB_INIT(&conf->roa); + RB_INIT(&conf->aspa); SIMPLEQ_INIT(&conf->as_sets); SIMPLEQ_INIT(&conf->rtrs); @@ -170,6 +171,27 @@ free_roatree(struct roa_tree *r) } } +void +free_aspa(struct aspa_set *aspa) +{ + if (aspa == NULL) + return; + free(aspa->tas); + free(aspa->tas_aid); + free(aspa); +} + +void +free_aspatree(struct aspa_tree *a) +{ + struct aspa_set *aspa, *naspa; + + RB_FOREACH_SAFE(aspa, aspa_tree, a, naspa) { + RB_REMOVE(aspa_tree, a, aspa); + free_aspa(aspa); + } +} + void free_rtrs(struct rtr_config_head *rh) { @@ -198,6 +220,7 @@ free_config(struct bgpd_config *conf) free_rde_prefixsets(&conf->rde_originsets); as_sets_free(&conf->as_sets); free_roatree(&conf->roa); + free_aspatree(&conf->aspa); free_rtrs(&conf->rtrs); while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) { @@ -267,6 +290,12 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf) RB_ROOT(&xconf->roa) = RB_ROOT(&conf->roa); RB_ROOT(&conf->roa) = NULL; + /* switch the aspa, first remove the old one */ + free_aspatree(&xconf->aspa); + /* then move the RB tree root */ + RB_ROOT(&xconf->aspa) = RB_ROOT(&conf->aspa); + RB_ROOT(&conf->aspa) = NULL; + /* switch the rtr_configs, first remove the old ones */ free_rtrs(&xconf->rtrs); SIMPLEQ_CONCAT(&xconf->rtrs, &conf->rtrs); @@ -582,7 +611,7 @@ prefixset_cmp(struct prefixset_item *a, struct prefixset_item *b) RB_GENERATE(prefixset_tree, prefixset_item, entry, prefixset_cmp); -int +static inline int roa_cmp(struct roa *a, struct roa *b) { int i; @@ -627,3 +656,15 @@ roa_cmp(struct roa *a, struct roa *b) } RB_GENERATE(roa_tree, roa, entry, roa_cmp); + +static inline int +aspa_cmp(struct aspa_set *a, struct aspa_set *b) +{ + if (a->as < b->as) + return (-1); + if (a->as > b->as) + return (1); + return (0); +} + +RB_GENERATE(aspa_tree, aspa_set, entry, aspa_cmp); diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index ce44288b993..a52ebdfaf72 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.436 2022/09/21 21:12:04 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.437 2022/11/18 10:17:23 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -140,6 +140,13 @@ struct filter_match_l { struct filter_prefixset *prefixset; } fmopts; +struct aspa_tas_l { + struct aspa_tas_l *next; + uint32_t as; + uint32_t num; + uint8_t aid; +}; + struct peer *alloc_peer(void); struct peer *new_peer(void); struct peer *new_group(void); @@ -171,6 +178,7 @@ static void add_roa_set(struct prefixset_item *, uint32_t, uint8_t, time_t); static struct rtr_config *get_rtr(struct bgpd_addr *); static int insert_rtr(struct rtr_config *); +static int merge_aspa_set(uint32_t, struct aspa_tas_l *, time_t); typedef struct { union { @@ -186,6 +194,7 @@ typedef struct { struct filter_as_l *filter_as; struct filter_set *filter_set; struct filter_set_head *filter_set_head; + struct aspa_tas_l *aspa_elm; struct { struct bgpd_addr prefix; uint8_t len; @@ -222,8 +231,8 @@ typedef struct { %token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE %token MAXCOMMUNITIES MAXEXTCOMMUNITIES MAXLARGECOMMUNITIES %token PREFIX PREFIXLEN PREFIXSET -%token ROASET ORIGINSET OVS EXPIRES -%token ASSET SOURCEAS TRANSITAS PEERAS MAXASLEN MAXASSEQ +%token ASPASET ROASET ORIGINSET OVS EXPIRES +%token ASSET SOURCEAS TRANSITAS PEERAS PROVIDERAS CUSTOMERAS MAXASLEN MAXASSEQ %token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF %token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN PRIORITY %token ERROR INCLUDE @@ -254,6 +263,7 @@ typedef struct { %type filter_prefix_m %type unaryop equalityop binaryop filter_as_type %type encspec +%type aspa_tas aspa_tas_l %% grammar : /* empty */ @@ -263,6 +273,7 @@ grammar : /* empty */ | grammar as_set '\n' | grammar prefixset '\n' | grammar roa_set '\n' + | grammar aspa_set '\n' | grammar origin_set '\n' | grammar rtr '\n' | grammar rib '\n' @@ -520,10 +531,8 @@ prefixset_item : prefix prefixlenop { roa_set : ROASET '{' optnl { curroatree = &conf->roa; - noexpires = 0; } roa_set_l optnl '}' { curroatree = NULL; - noexpires = 1; } | ROASET '{' optnl '}' /* nothing */ ; @@ -540,6 +549,7 @@ origin_set : ORIGINSET STRING '{' optnl { SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry); curoset = NULL; curroatree = NULL; + noexpires = 0; } | ORIGINSET STRING '{' optnl '}' { if ((curoset = new_prefix_set($2, 1)) == NULL) { @@ -586,6 +596,55 @@ roa_set_l : prefixset_item SOURCEAS as4number_any expires { } ; +aspa_set : ASPASET '{' optnl aspa_set_l optnl '}' + | ASPASET '{' optnl '}' + ; + +aspa_set_l : aspa_elm + | aspa_set_l comma aspa_elm + ; + +aspa_elm : CUSTOMERAS as4number expires PROVIDERAS '{' optnl + aspa_tas_l optnl '}' { + int rv; + struct aspa_tas_l *a, *n; + + rv = merge_aspa_set($2, $7, $3); + + for (a = $7; a != NULL; a = n) { + n = a->next; + free(a); + } + + if (rv == -1) + YYERROR; + } + ; + +aspa_tas_l : aspa_tas { $$ = $1; } + | aspa_tas_l comma aspa_tas { + $3->next = $1; + $3->num = $1->num + 1; + $$ = $3; + } + ; + +aspa_tas : as4number_any { + if (($$ = calloc(1, sizeof(*$$))) == NULL) + fatal(NULL); + $$->as = $1; + $$->aid = AID_UNSPEC; + $$->num = 1; + } + | as4number_any ALLOW family { + if (($$ = calloc(1, sizeof(*$$))) == NULL) + fatal(NULL); + $$->as = $1; + $$->aid = $3; + $$->num = 1; + } + ; + rtr : RTR address { currtr = get_rtr(&$2); currtr->remote_port = RTR_PORT; @@ -609,6 +668,7 @@ rtr : RTR address { rtropt_l : rtropt | rtropt_l optnl rtropt + ; rtropt : DESCR STRING { if (strlcpy(currtr->descr, $2, @@ -3090,12 +3150,14 @@ lookup(char *s) { "as-4byte", AS4BYTE }, { "as-override", ASOVERRIDE}, { "as-set", ASSET }, + { "aspa-set", ASPASET}, { "blackhole", BLACKHOLE}, { "capabilities", CAPABILITIES}, { "community", COMMUNITY}, { "compare", COMPARE}, { "connect-retry", CONNECTRETRY}, { "connected", CONNECTED}, + { "customer-as", CUSTOMERAS}, { "default-route", DEFAULTROUTE}, { "delete", DELETE}, { "demote", DEMOTE}, @@ -3173,6 +3235,7 @@ lookup(char *s) { "prepend-neighbor", PREPEND_PEER}, { "prepend-self", PREPEND_SELF}, { "priority", PRIORITY}, + { "provider-as", PROVIDERAS}, { "qualify", QUALIFY}, { "quick", QUICK}, { "rd", RD}, @@ -4999,3 +5062,57 @@ insert_rtr(struct rtr_config *new) return 0; } + +static int +merge_aspa_set(uint32_t as, struct aspa_tas_l *tas, time_t expires) +{ + struct aspa_set *aspa, needle = { .as = as }; + uint32_t i, num, *newtas; + uint8_t *newtasaid = NULL; + + aspa = RB_FIND(aspa_tree, &conf->aspa, &needle); + if (aspa == NULL) { + if ((aspa = calloc(1, sizeof(*aspa))) == NULL) { + yyerror("out of memory"); + return -1; + } + aspa->as = as; + aspa->expires = expires; + RB_INSERT(aspa_tree, &conf->aspa, aspa); + } + + if (UINT32_MAX - aspa->num <= tas->num) { + yyerror("aspa_set overflow"); + return -1; + } + num = aspa->num + tas->num; + newtas = recallocarray(aspa->tas, aspa->num, num, sizeof(uint32_t)); + if (newtas == NULL) { + yyerror("out of memory"); + return -1; + } + newtasaid = recallocarray(aspa->tas_aid, aspa->num, num, 1); + if (newtasaid == NULL) { + free(newtas); + yyerror("out of memory"); + return -1; + } + + /* fill starting at the end since the tas list is reversed */ + if (num > 0) { + for (i = num - 1; tas; tas = tas->next, i--) { + newtas[i] = tas->as; + if (tas->aid != AID_UNSPEC) + newtasaid[i] = tas->aid; + } + } + + aspa->num = num; + aspa->tas = newtas; + aspa->tas_aid = newtasaid; + /* take the longest expiry time, same logic as for ROA entries */ + if (aspa->expires != 0 && expires != 0 && expires > aspa->expires) + aspa->expires = expires; + + return 0; +} diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index 605ed0009a7..461a3c46d08 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.159 2022/09/21 21:12:04 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.160 2022/11/18 10:17:23 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -42,6 +42,7 @@ void print_as_sets(struct as_set_head *); void print_prefixsets(struct prefixset_head *); void print_originsets(struct prefixset_head *); void print_roa(struct roa_tree *); +void print_aspa(struct aspa_tree *); void print_rtrs(struct rtr_config_head *); void print_peer(struct peer_config *, struct bgpd_config *, const char *); @@ -590,6 +591,33 @@ print_roa(struct roa_tree *r) printf("\n}\n\n"); } +void +print_aspa(struct aspa_tree *a) +{ + struct aspa_set *aspa; + uint32_t i; + + if (RB_EMPTY(a)) + return; + + printf("aspa-set {"); + RB_FOREACH(aspa, aspa_tree, a) { + printf("\n\t"); + printf("customer-as %s", log_as(aspa->as)); + if (aspa->expires != 0) + printf(" expires %lld", (long long)aspa->expires); + printf(" provider-as { "); + for (i = 0; i < aspa->num; i++) { + printf("%s ", log_as(aspa->tas[i])); + if (aspa->tas_aid != NULL && + aspa->tas_aid[i] != AID_UNSPEC) + printf("allow %s ", print_af(aspa->tas_aid[i])); + } + printf("}"); + } + printf("\n}\n\n"); +} + void print_rtrs(struct rtr_config_head *rh) { @@ -1096,6 +1124,7 @@ print_config(struct bgpd_config *conf, struct rib_names *rib_l) print_mainconf(conf); print_rtrs(&conf->rtrs); print_roa(&conf->roa); + print_aspa(&conf->aspa); print_as_sets(&conf->as_sets); print_prefixsets(&conf->prefixsets); print_originsets(&conf->originsets); diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 1d9730b9111..b6fd6d3f58e 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.579 2022/11/07 22:48:35 mbuhl Exp $ */ +/* $OpenBSD: rde.c,v 1.580 2022/11/18 10:17:23 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -323,6 +323,11 @@ rde_main(int debug, int verbose) close(ibuf_se_ctl->fd); free(ibuf_se_ctl); } + if (ibuf_rtr) { + msgbuf_clear(&ibuf_rtr->w); + close(ibuf_rtr->fd); + free(ibuf_rtr); + } msgbuf_clear(&ibuf_main->w); close(ibuf_main->fd); free(ibuf_main); diff --git a/usr.sbin/bgpd/rtr.c b/usr.sbin/bgpd/rtr.c index 0960f24c16a..cd3756f88f4 100644 --- a/usr.sbin/bgpd/rtr.c +++ b/usr.sbin/bgpd/rtr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rtr.c,v 1.8 2022/10/18 09:30:29 job Exp $ */ +/* $OpenBSD: rtr.c,v 1.9 2022/11/18 10:17:23 claudio Exp $ */ /* * Copyright (c) 2020 Claudio Jeker @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -80,6 +81,24 @@ rtr_expire_roas(time_t now) return recalc; } +static unsigned int +rtr_expire_aspa(time_t now) +{ + struct aspa_set *aspa, *na; + unsigned int recalc = 0; + + RB_FOREACH_SAFE(aspa, aspa_tree, &conf->aspa, na) { + if (aspa->expires != 0 && aspa->expires <= now) { + recalc++; + RB_REMOVE(aspa_tree, &conf->aspa, aspa); + free_aspa(aspa); + } + } + if (recalc != 0) + log_info("%u aspa-set entries expired", recalc); + return recalc; +} + void roa_insert(struct roa_tree *rt, struct roa *in) { @@ -193,6 +212,8 @@ rtr_main(int debug, int verbose) EXPIRE_TIMEOUT); if (rtr_expire_roas(time(NULL)) != 0) rtr_recalc(); + if (rtr_expire_aspa(time(NULL)) != 0) + rtr_recalc(); } } @@ -218,10 +239,11 @@ rtr_main(int debug, int verbose) static void rtr_dispatch_imsg_parent(struct imsgbuf *ibuf) { - struct imsg imsg; - struct roa *roa; - struct rtr_session *rs; - int n, fd; + static struct aspa_set *aspa; + struct imsg imsg; + struct roa *roa; + struct rtr_session *rs; + int n, fd; while (ibuf) { if ((n = imsg_get(ibuf, &imsg)) == -1) @@ -274,6 +296,48 @@ rtr_dispatch_imsg_parent(struct imsgbuf *ibuf) fatalx("IMSG_RECONF_ROA_ITEM bad len"); roa_insert(&nconf->roa, imsg.data); break; + case IMSG_RECONF_ASPA: + if (imsg.hdr.len - IMSG_HEADER_SIZE != + offsetof(struct aspa_set, tas)) + fatalx("IMSG_RECONF_ASPA bad len"); + if (aspa != NULL) + fatalx("unexpected IMSG_RECONF_ASPA"); + if ((aspa = calloc(1, sizeof(*aspa))) == NULL) + fatal("aspa alloc"); + memcpy(aspa, imsg.data, offsetof(struct aspa_set, tas)); + break; + case IMSG_RECONF_ASPA_TAS: + if (aspa == NULL) + fatalx("unexpected IMSG_RECONF_ASPA_TAS"); + if (imsg.hdr.len - IMSG_HEADER_SIZE != + aspa->num * sizeof(*aspa->tas)) + fatalx("IMSG_RECONF_ASPA_TAS bad len"); + aspa->tas = reallocarray(NULL, aspa->num, + sizeof(*aspa->tas)); + if (aspa->tas == NULL) + fatal("aspa tas alloc"); + memcpy(aspa->tas, imsg.data, + aspa->num * sizeof(*aspa->tas)); + break; + case IMSG_RECONF_ASPA_TAS_AID: + if (aspa == NULL) + fatalx("unexpected IMSG_RECONF_ASPA_TAS_ID"); + if (imsg.hdr.len - IMSG_HEADER_SIZE != aspa->num) + fatalx("IMSG_RECONF_ASPA_TAS_AID bad len"); + aspa->tas_aid = malloc(aspa->num); + if (aspa->tas_aid == NULL) + fatal("aspa tas aid alloc"); + memcpy(aspa->tas_aid, imsg.data, aspa->num); + break; + case IMSG_RECONF_ASPA_DONE: + if (aspa == NULL) + fatalx("unexpected IMSG_RECONF_ASPA_DONE"); + if (RB_INSERT(aspa_tree, &nconf->aspa, aspa) != NULL) { + log_warnx("duplicate ASPA set received"); + free_aspa(aspa); + } + aspa = NULL; + break; case IMSG_RECONF_RTR_CONFIG: if (imsg.hdr.len - IMSG_HEADER_SIZE != PEER_DESCR_LEN) fatalx("IMSG_RECONF_RTR_CONFIG bad len"); @@ -296,9 +360,15 @@ rtr_dispatch_imsg_parent(struct imsgbuf *ibuf) /* then move the RB tree root */ RB_ROOT(&conf->roa) = RB_ROOT(&nconf->roa); RB_ROOT(&nconf->roa) = NULL; + /* switch the aspa tree, first remove the old one */ + free_aspatree(&conf->aspa); + /* then move the RB tree root */ + RB_ROOT(&conf->aspa) = RB_ROOT(&nconf->aspa); + RB_ROOT(&nconf->aspa) = NULL; /* finally merge the rtr session */ rtr_config_merge(); rtr_expire_roas(time(NULL)); + rtr_expire_aspa(time(NULL)); rtr_recalc(); log_info("RTR engine reconfigured"); imsg_compose(ibuf_main, IMSG_RECONF_DONE, 0, 0, @@ -347,6 +417,77 @@ rtr_imsg_compose(int type, uint32_t id, pid_t pid, void *data, size_t datalen) imsg_compose(ibuf_main, type, id, pid, -1, data, datalen); } +/* + * Add an asnum to the aspa_set. The aspa_set is sorted by asnum. + * The aid is altered into a bitmask to simplify the merge of entries + * that just use a different aid. + */ +static void +aspa_set_entry(struct aspa_set *aspa, uint32_t asnum, uint8_t aid) +{ + uint32_t i, num, *newtas; + uint8_t *newtasaid; + + switch (aid) { + case AID_INET: + aid = 0x1; + break; + case AID_INET6: + aid = 0x2; + break; + case AID_UNSPEC: + aid = 0x3; + break; + default: + fatalx("aspa_set bad AID"); + } + + for (i = 0; i < aspa->num; i++) { + if (asnum < aspa->tas[i] || aspa->tas[i] == 0) + break; + if (asnum == aspa->tas[i]) { + aspa->tas_aid[i] |= aid; + return; + } + } + + num = aspa->num + 1; + newtas = recallocarray(aspa->tas, aspa->num, num, sizeof(uint32_t)); + newtasaid = recallocarray(aspa->tas_aid, aspa->num, num, 1); + if (newtas == NULL || newtasaid == NULL) + fatal("aspa_set merge"); + + if (i < aspa->num) { + memmove(newtas + i + 1, newtas + i, + (aspa->num - i) * sizeof(uint32_t)); + memmove(newtasaid + i + 1, newtasaid + i, (aspa->num - i)); + } + newtas[i] = asnum; + newtasaid[i] = aid; + + aspa->num = num; + aspa->tas = newtas; + aspa->tas_aid = newtasaid; +} + +static void +rtr_aspa_merge_set(struct aspa_tree *a, struct aspa_set *mergeset) +{ + struct aspa_set *aspa, needle = { .as = mergeset->as }; + uint32_t i; + + aspa = RB_FIND(aspa_tree, a, &needle); + if (aspa == NULL) { + if ((aspa = calloc(1, sizeof(*aspa))) == NULL) + fatal("aspa insert"); + aspa->as = mergeset->as; + RB_INSERT(aspa_tree, a, aspa); + } + + for (i = 0; i < mergeset->num; i++) + aspa_set_entry(aspa, mergeset->tas[i], mergeset->tas_aid[i]); +} + /* * Merge all RPKI ROA trees into one as one big union. * Simply try to add all roa entries into a new RB tree. @@ -356,9 +497,12 @@ void rtr_recalc(void) { struct roa_tree rt; + struct aspa_tree at; struct roa *roa, *nr; + struct aspa_set *aspa; RB_INIT(&rt); + RB_INIT(&at); RB_FOREACH(roa, roa_tree, &conf->roa) roa_insert(&rt, roa); @@ -371,5 +515,11 @@ rtr_recalc(void) roa, sizeof(*roa)); free(roa); } + + RB_FOREACH(aspa, aspa_tree, &conf->aspa) + rtr_aspa_merge_set(&at, aspa); + + free_aspatree(&at); + imsg_compose(ibuf_rde, IMSG_RECONF_DONE, 0, 0, -1, NULL, 0); }