On Wed, Nov 16, 2022 at 03:37:31PM +0100, Claudio Jeker wrote: > On Wed, Nov 16, 2022 at 02:52:59PM +0100, Theo Buehler wrote: > > On Wed, Nov 16, 2022 at 12:47:46PM +0100, Claudio Jeker wrote: > > > ASPA sets are the 2nd thing that will be generated out of rpki (and > > > rpki-client). ASPA is used to further prevent leaks by providing customer > > > provider attestation (and blocking paths which violate these > > > attestations). > > > > > > I started to implement this and while this code does no checks yet it is > > > enough plumbing to parse and "merge" the ASPA sets. Similar to the roa-set > > > an aspa-set in the config will be parsed and passed to the rtr process > > > where it will be merged with the data from RTR sessions. > > > What is missing is all the code needed in the RDE to do the lookups. > > > > > > A aspa-set is defined like this: > > > aspa-set { > > > source-as 1 transit-as { 5 } > > > source-as 2 expires 1668181648 transit-as { 3 4 } > > > source-as 5 transit-as { 1 2 allow inet 7 allow inet6 } > > > } > > > > Adding this to the end of the default bgpd.conf I get > > > > /tmp/bgpd.conf:134: syntax error, expires not allowed > > /tmp/bgpd.conf:136: syntax error > > > > Deleting the expire time, it parses fine. I suspect the duplicate > > aspa_set rules in parse.y don't work as intended. > > No this is actually the roa-set code that triggers this. It changes > noexpires to 1 and then after that aspa-set fails. > I changed to code to set noexpires in the origin-set case (where expires > is not allowed) and then set it back to 0 when leaving that node.
So here is an updated version that should fix all of the remarks from tb@ Also I changed 'transit-as' to 'upstream-as'. As you can guess I'm not a fan of the terms customer and provider. -- :wq Claudio Index: bgpd.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v retrieving revision 1.254 diff -u -p -r1.254 bgpd.c --- bgpd.c 17 Aug 2022 15:15:25 -0000 1.254 +++ bgpd.c 16 Nov 2022 14:45:23 -0000 @@ -27,6 +27,7 @@ #include <poll.h> #include <pwd.h> #include <signal.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -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) Index: bgpd.h =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v retrieving revision 1.454 diff -u -p -r1.454 bgpd.h --- bgpd.h 23 Sep 2022 15:50:41 -0000 1.454 +++ bgpd.h 15 Nov 2022 11:22:41 -0000 @@ -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_h 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); Index: config.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/config.c,v retrieving revision 1.104 diff -u -p -r1.104 config.c --- config.c 17 Aug 2022 15:15:25 -0000 1.104 +++ config.c 15 Nov 2022 11:22:18 -0000 @@ -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); @@ -171,6 +172,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) { struct rtr_config *r; @@ -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, 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, 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); Index: parse.y =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v retrieving revision 1.436 diff -u -p -r1.436 parse.y --- parse.y 21 Sep 2022 21:12:04 -0000 1.436 +++ parse.y 16 Nov 2022 16:01:09 -0000 @@ -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 prefixse 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 UPSTREAMAS 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 <v.filter_prefix> filter_prefix_m %type <v.u8> unaryop equalityop binaryop filter_as_type %type <v.encspec> encspec +%type <v.aspa_elm> 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 as4n } ; +aspa_set : ASPASET '{' optnl aspa_set_l optnl '}' + | ASPASET '{' optnl '}' + ; + +aspa_set_l : aspa_elm + | aspa_set_l comma aspa_elm + ; + +aspa_elm : SOURCEAS as4number expires UPSTREAMAS '{' 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,6 +3150,7 @@ lookup(char *s) { "as-4byte", AS4BYTE }, { "as-override", ASOVERRIDE}, { "as-set", ASSET }, + { "aspa-set", ASPASET}, { "blackhole", BLACKHOLE}, { "capabilities", CAPABILITIES}, { "community", COMMUNITY}, @@ -3203,6 +3264,7 @@ lookup(char *s) { "transparent-as", TRANSPARENT}, { "ttl-security", TTLSECURITY}, { "unicast", UNICAST}, + { "upstream-as", UPSTREAMAS}, { "via", VIA}, { "vpn", VPN}, { "weight", WEIGHT} @@ -4996,6 +5058,60 @@ insert_rtr(struct rtr_config *new) new->id = ++id; SIMPLEQ_INSERT_TAIL(&conf->rtrs, currtr, entry); + + 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; } Index: printconf.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v retrieving revision 1.159 diff -u -p -r1.159 printconf.c --- printconf.c 21 Sep 2022 21:12:04 -0000 1.159 +++ printconf.c 16 Nov 2022 16:02:20 -0000 @@ -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 *); @@ -591,6 +592,33 @@ print_roa(struct roa_tree *r) } 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("source-as %s", log_as(aspa->as)); + if (aspa->expires != 0) + printf(" expires %lld", (long long)aspa->expires); + printf(" upstream-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 ", aid2str(aspa->tas_aid[i])); + } + printf("}"); + } + printf("\n}\n\n"); +} + +void print_rtrs(struct rtr_config_head *rh) { struct rtr_config *r; @@ -1096,6 +1124,7 @@ print_config(struct bgpd_config *conf, s 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); Index: rde.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v retrieving revision 1.579 diff -u -p -r1.579 rde.c --- rde.c 7 Nov 2022 22:48:35 -0000 1.579 +++ rde.c 9 Nov 2022 14:18:16 -0000 @@ -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); Index: rtr.c =================================================================== RCS file: /cvs/src/usr.sbin/bgpd/rtr.c,v retrieving revision 1.8 diff -u -p -r1.8 rtr.c --- rtr.c 18 Oct 2022 09:30:29 -0000 1.8 +++ rtr.c 16 Nov 2022 14:47:40 -0000 @@ -20,6 +20,7 @@ #include <poll.h> #include <pwd.h> #include <signal.h> +#include <stddef.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> @@ -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 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 /* 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, @@ -348,6 +418,77 @@ rtr_imsg_compose(int type, uint32_t id, } /* + * 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. * This could be made a fair bit faster but for now this is good enough. @@ -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); }