diff options
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/bgpd/bgpd.c | 33 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.h | 21 | ||||
-rw-r--r-- | usr.sbin/bgpd/config.c | 45 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 127 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 31 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 7 | ||||
-rw-r--r-- | usr.sbin/bgpd/rtr.c | 160 |
7 files changed, 399 insertions, 25 deletions
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 <henning@openbsd.org> @@ -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) 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 <henning@openbsd.org> @@ -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 <henning@openbsd.org> @@ -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, 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 <henning@openbsd.org> @@ -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 <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 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 <henning@openbsd.org> @@ -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("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) { struct rtr_config *r; @@ -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 <henning@openbsd.org> @@ -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 <claudio@openbsd.org> @@ -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 *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, @@ -348,6 +418,77 @@ rtr_imsg_compose(int type, uint32_t id, pid_t pid, void *data, size_t 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. * 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); } |