On Thu, Sep 20, 2018 at 01:56:04PM +0200, Claudio Jeker wrote:
> This is the next step for ROA validation.
>
> Implement code to parse, print and reload roa-set tables.
> This is sharing a lot of code with prefixset which makes all a bit easier.
> A roa-set is defined like this:
> roa-set "test2" {
> 1.2.3.0/24 source-as 1,
> 1.2.8.0/22 source-as 3
> }
>
Shouldn't roa-set include maxlen ?
> This does not include any code to acutally use the data yet, I'm working
> on that now and that will be then the next and hopefully last diff to
> support ROA validations in bgpd.
> --
> :wq Claudio
>
>
> Index: bgpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
> retrieving revision 1.200
> diff -u -p -r1.200 bgpd.c
> --- bgpd.c 20 Sep 2018 11:45:59 -0000 1.200
> +++ bgpd.c 20 Sep 2018 11:49:56 -0000
> @@ -516,6 +516,34 @@ reconfigure(char *conffile, struct bgpd_
> if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSETITEM, 0,
> 0, -1, psi, sizeof(*psi)) == -1)
> return (-1);
> + set_free(psi->set);
> + free(psi);
> + }
> + free(ps);
> + }
> +
> + /* roasets for filters in the RDE */
> + while ((ps = SIMPLEQ_FIRST(conf->roasets)) != NULL) {
> + SIMPLEQ_REMOVE_HEAD(conf->roasets, entry);
> + if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_SET, 0, 0, -1,
> + ps->name, sizeof(ps->name)) == -1)
> + return (-1);
> + RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) {
> + u_int32_t *as;
> + size_t i, l, n;
> + RB_REMOVE(prefixset_tree, &ps->psitems, psi);
> + as = set_get(psi->set, &n);
> + for (i = 0; i < n; i += l) {
> + l = (n - i > 1024 ? 1024 : n - i);
> + if (imsg_compose(ibuf_rde,
> + IMSG_RECONF_ROA_AS_SET_ITEMS,
> + 0, 0, -1, as + i, l) == -1)
> + return -1;
> + }
> + if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSETITEM, 0,
> + 0, -1, psi, sizeof(*psi)) == -1)
> + return (-1);
> + set_free(psi->set);
> free(psi);
> }
> free(ps);
> Index: bgpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
> retrieving revision 1.343
> diff -u -p -r1.343 bgpd.h
> --- bgpd.h 20 Sep 2018 11:45:59 -0000 1.343
> +++ bgpd.h 20 Sep 2018 11:49:56 -0000
> @@ -229,7 +229,9 @@ struct bgpd_config {
> struct listen_addrs *listen_addrs;
> struct mrt_head *mrt;
> struct prefixset_head *prefixsets;
> + struct prefixset_head *roasets;
> struct rde_prefixset_head *rde_prefixsets;
> + struct rde_prefixset_head *rde_roasets;
> struct as_set_head *as_sets;
> char *csock;
> char *rcsock;
> @@ -431,6 +433,8 @@ enum imsg_type {
> IMSG_RECONF_AS_SET,
> IMSG_RECONF_AS_SET_ITEMS,
> IMSG_RECONF_AS_SET_DONE,
> + IMSG_RECONF_ROA_SET,
> + IMSG_RECONF_ROA_AS_SET_ITEMS,
> IMSG_RECONF_DONE,
> IMSG_UPDATE,
> IMSG_UPDATE_ERR,
> @@ -961,6 +965,7 @@ struct roa_set {
> struct prefixset_item {
> struct filter_prefix p;
> RB_ENTRY(prefixset_item) entry;
> + struct set_table *set;
> };
> RB_HEAD(prefixset_tree, prefixset_item);
>
> Index: config.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/config.c,v
> retrieving revision 1.74
> diff -u -p -r1.74 config.c
> --- config.c 20 Sep 2018 07:46:39 -0000 1.74
> +++ config.c 20 Sep 2018 11:49:56 -0000
> @@ -67,6 +67,8 @@ new_config(void)
> if ((conf->prefixsets = calloc(1, sizeof(struct prefixset_head)))
> == NULL)
> fatal(NULL);
> + if ((conf->roasets = calloc(1, sizeof(struct prefixset_head))) == NULL)
> + fatal(NULL);
> if ((conf->as_sets = calloc(1, sizeof(struct as_set_head))) == NULL)
> fatal(NULL);
> if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL)
> @@ -81,6 +83,7 @@ new_config(void)
> TAILQ_INIT(&conf->networks);
> SIMPLEQ_INIT(&conf->rdomains);
> SIMPLEQ_INIT(conf->prefixsets);
> + SIMPLEQ_INIT(conf->roasets);
> SIMPLEQ_INIT(conf->as_sets);
>
> TAILQ_INIT(conf->filters);
> @@ -129,6 +132,7 @@ free_prefixsets(struct prefixset_head *p
> ps = SIMPLEQ_FIRST(psh);
> RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) {
> RB_REMOVE(prefixset_tree, &ps->psitems, psi);
> + set_free(psi->set);
> free(psi);
> }
> SIMPLEQ_REMOVE_HEAD(psh, entry);
> @@ -147,6 +151,7 @@ free_config(struct bgpd_config *conf)
> free_networks(&conf->networks);
> filterlist_free(conf->filters);
> free_prefixsets(conf->prefixsets);
> + free_prefixsets(conf->roasets);
> as_sets_free(conf->as_sets);
>
> while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
> @@ -224,6 +229,11 @@ merge_config(struct bgpd_config *xconf,
> free_prefixsets(xconf->prefixsets);
> xconf->prefixsets = conf->prefixsets;
> conf->prefixsets = NULL;
> +
> + /* switch the roasets, first remove the old ones */
> + free_prefixsets(xconf->roasets);
> + xconf->roasets = conf->roasets;
> + conf->roasets = NULL;
>
> /* switch the as_sets, first remove the old ones */
> as_sets_free(xconf->as_sets);
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
> retrieving revision 1.355
> diff -u -p -r1.355 parse.y
> --- parse.y 20 Sep 2018 11:45:59 -0000 1.355
> +++ parse.y 20 Sep 2018 11:49:57 -0000
> @@ -93,6 +93,7 @@ static struct peer *curpeer;
> static struct peer *curgroup;
> static struct rdomain *currdom;
> static struct prefixset *curpset;
> +static struct prefixset *curroaset;
> static struct filter_head *filter_l;
> static struct filter_head *peerfilter_l;
> static struct filter_head *groupfilter_l;
> @@ -162,7 +163,8 @@ int parseextcommunity(struct filter_ex
> static int new_as_set(char *);
> static void add_as_set(u_int32_t);
> static void done_as_set(void);
> -static int new_prefix_set(char *);
> +static struct prefixset *new_prefix_set(char *, int);
> +static void add_roa_set(struct prefixset_item *, u_int32_t, u_int8_t);
>
> typedef struct {
> union {
> @@ -211,7 +213,7 @@ typedef struct {
> %token FROM TO ANY
> %token CONNECTED STATIC
> %token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE
> -%token PREFIX PREFIXLEN PREFIXSET
> +%token PREFIX PREFIXLEN PREFIXSET ROASET
> %token ASSET SOURCEAS TRANSITAS PEERAS MAXASLEN MAXASSEQ
> %token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
> %token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN PRIORITY
> @@ -250,6 +252,7 @@ grammar : /* empty */
> | grammar include '\n'
> | grammar as_set '\n'
> | grammar prefixset '\n'
> + | grammar roa_set '\n'
> | grammar conf_main '\n'
> | grammar rdomain '\n'
> | grammar neighbor '\n'
> @@ -423,7 +426,7 @@ as_set_l : as4number_any { add_as_set(
> | as_set_l comma as4number_any { add_as_set($3); }
>
> prefixset : PREFIXSET STRING '{' optnl {
> - if (new_prefix_set($2) != 0) {
> + if ((curpset = new_prefix_set($2, 0)) == NULL) {
> free($2);
> YYERROR;
> }
> @@ -433,7 +436,7 @@ prefixset : PREFIXSET STRING '{' optnl
> curpset = NULL;
> }
> | PREFIXSET STRING '{' optnl '}' {
> - if (new_prefix_set($2) != 0) {
> + if ((curpset = new_prefix_set($2, 0)) == NULL) {
> free($2);
> YYERROR;
> }
> @@ -487,6 +490,47 @@ prefixset_item : prefix prefixlenop
> {
> }
> ;
>
> +roa_set : ROASET STRING '{' optnl {
> + if ((curroaset = new_prefix_set($2, 1)) == NULL) {
> + free($2);
> + YYERROR;
> + }
> + free($2);
> + } roa_set_l optnl '}' {
> + SIMPLEQ_INSERT_TAIL(conf->roasets, curroaset, entry);
> + curroaset = NULL;
> + }
> + | ROASET STRING '{' optnl '}' {
> + if ((curroaset = new_prefix_set($2, 1)) == NULL) {
> + free($2);
> + YYERROR;
> + }
> + free($2);
> + SIMPLEQ_INSERT_TAIL(conf->roasets, curroaset, entry);
> + curroaset = NULL;
> + }
> + ;
> +
> +roa_set_l : prefixset_item SOURCEAS as4number_any {
> + if ($1->p.len_min != $1->p.len) {
> + yyerror("unsupported prefixlen operation in "
> + "roa-set");
> + free($1);
> + YYERROR;
> + }
> + add_roa_set($1, $3, $1->p.len_max);
> + }
> + | roa_set_l comma prefixset_item SOURCEAS as4number_any {
> + if ($3->p.len_min != $3->p.len) {
> + yyerror("unsupported prefixlen operation in "
> + "roa-set");
> + free($3);
> + YYERROR;
> + }
> + add_roa_set($3, $5, $3->p.len_max);
> + }
> + ;
> +
> conf_main : AS as4number {
> conf->as = $2;
> if ($2 > USHRT_MAX)
> @@ -2768,6 +2812,7 @@ lookup(char *s)
> { "restart", RESTART},
> { "restricted", RESTRICTED},
> { "rib", RIB},
> + { "roa-set", ROASET },
> { "route-collector", ROUTECOLL},
> { "route-reflector", REFLECTOR},
> { "router-id", ROUTERID},
> @@ -4230,21 +4275,52 @@ done_as_set(void)
> curset = NULL;
> }
>
> -static int
> -new_prefix_set(char *name)
> +static struct prefixset *
> +new_prefix_set(char *name, int is_roa)
> {
> - if (find_prefixset(name, conf->prefixsets) != NULL) {
> - yyerror("prefix-set \"%s\" already exists", name);
> - return -1;
> + const char *type = "prefix-set";
> + struct prefixset_head *sets = conf->prefixsets;
> + struct prefixset *pset;
> +
> + if (is_roa) {
> + type = "roa-set";
> + sets = conf->roasets;
> }
> - if ((curpset = calloc(1, sizeof(*curpset))) == NULL)
> +
> + if (find_prefixset(name, sets) != NULL) {
> + yyerror("%s \"%s\" already exists", type, name);
> + return NULL;
> + }
> + if ((pset = calloc(1, sizeof(*pset))) == NULL)
> fatal("prefixset");
> - if (strlcpy(curpset->name, name, sizeof(curpset->name)) >=
> - sizeof(curpset->name)) {
> + if (strlcpy(pset->name, name, sizeof(pset->name)) >=
> + sizeof(pset->name)) {
> yyerror("prefix-set \"%s\" too long: max %zu",
> - name, sizeof(curpset->name) - 1);
> - return -1;
> + name, sizeof(pset->name) - 1);
> + free(pset);
> + return NULL;
> }
> - RB_INIT(&curpset->psitems);
> - return 0;
> + RB_INIT(&pset->psitems);
> + return pset;
> +}
> +
> +static void
> +add_roa_set(struct prefixset_item *npsi, u_int32_t as, u_int8_t max)
> +{
> + struct prefixset_item *psi;
> + struct roa_set rs;
> +
> + /* no prefixlen option on this tree */
> + npsi->p.len_max = npsi->p.len_min = npsi->p.len;
> + psi = RB_INSERT(prefixset_tree, &curroaset->psitems, npsi);
> + if (psi == NULL)
> + psi = npsi;
> +
> + if (psi->set == NULL)
> + if ((psi->set = set_new(1, sizeof(rs))) == NULL)
> + fatal("set_new");
> + rs.as = as;
> + rs.maxlen = max;
> + if (set_add(psi->set, &rs, 1) != 0)
> + fatal("as_set_new");
> }
> Index: printconf.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
> retrieving revision 1.121
> diff -u -p -r1.121 printconf.c
> --- printconf.c 20 Sep 2018 11:45:59 -0000 1.121
> +++ printconf.c 20 Sep 2018 11:49:57 -0000
> @@ -42,6 +42,7 @@ const char *print_af(u_int8_t);
> void print_network(struct network_config *, const char *);
> void print_as_sets(struct as_set_head *);
> void print_prefixsets(struct prefixset_head *);
> +void print_roasets(struct prefixset_head *);
> void print_peer(struct peer_config *, struct bgpd_config *,
> const char *);
> const char *print_auth_alg(u_int8_t);
> @@ -486,6 +487,35 @@ print_prefixsets(struct prefixset_head *
> }
>
> void
> +print_roasets(struct prefixset_head *psh)
> +{
> + struct prefixset *ps;
> + struct prefixset_item *psi;
> + struct roa_set *rs;
> + size_t i, n;
> +
> + SIMPLEQ_FOREACH(ps, psh, entry) {
> + int count = 0;
> + printf("roa-set \"%s\" {", ps->name);
> + RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
> + rs = set_get(psi->set, &n);
> + for (i = 0; i < n; i++) {
> + if (count++ % 2 == 0)
> + printf("\n\t");
> + else
> + printf(", ");
> +
> + print_prefix(&psi->p);
> + if (psi->p.len != rs[i].maxlen)
> + printf(" maxlen %u", rs[i].maxlen);
> + printf(" source-as %u", rs[i].as);
> + }
> + }
> + printf("\n}\n\n");
> + }
> +}
> +
> +void
> print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
> {
> char *method;
> @@ -891,6 +921,7 @@ print_config(struct bgpd_config *conf, s
> print_mainconf(conf);
> print_prefixsets(conf->prefixsets);
> print_as_sets(conf->as_sets);
> + print_roasets(conf->roasets);
> TAILQ_FOREACH(n, net_l, entry)
> print_network(&n->net, "");
> if (!SIMPLEQ_EMPTY(rdom_l))
> Index: rde.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
> retrieving revision 1.425
> diff -u -p -r1.425 rde.c
> --- rde.c 20 Sep 2018 11:45:59 -0000 1.425
> +++ rde.c 20 Sep 2018 11:49:57 -0000
> @@ -131,6 +131,7 @@ time_t reloadtime;
> struct rde_peer_head peerlist;
> struct rde_peer *peerself;
> struct rde_prefixset_head *prefixsets_tmp, *prefixsets_old;
> +struct rde_prefixset_head *roasets_tmp, *roasets_old;
> struct as_set_head *as_sets_tmp, *as_sets_old;
> struct filter_head *out_rules, *out_rules_tmp;
> struct rdomain_head *rdomains_l, *newdomains;
> @@ -689,6 +690,7 @@ rde_dispatch_imsg_parent(struct imsgbuf
> {
> static struct rde_prefixset *last_prefixset;
> static struct as_set *last_as_set;
> + static struct set_table *last_set;
> static struct rdomain *rd;
> struct imsg imsg;
> struct mrt xmrt;
> @@ -702,7 +704,7 @@ rde_dispatch_imsg_parent(struct imsgbuf
> struct prefixset_item psi;
> char *name;
> size_t nmemb;
> - int n, fd;
> + int n, fd, rv;
> u_int16_t rid;
>
> while (ibuf) {
> @@ -774,6 +776,11 @@ rde_dispatch_imsg_parent(struct imsgbuf
> if (prefixsets_tmp == NULL)
> fatal(NULL);
> SIMPLEQ_INIT(prefixsets_tmp);
> + roasets_tmp = calloc(1,
> + sizeof(struct rde_prefixset_head));
> + if (roasets_tmp == NULL)
> + fatal(NULL);
> + SIMPLEQ_INIT(roasets_tmp);
> as_sets_tmp = calloc(1,
> sizeof(struct as_set_head));
> if (as_sets_tmp == NULL)
> @@ -877,6 +884,7 @@ rde_dispatch_imsg_parent(struct imsgbuf
> TAILQ_INSERT_TAIL(out_rules_tmp, r, entry);
> break;
> case IMSG_RECONF_PREFIXSET:
> + case IMSG_RECONF_ROA_SET:
> if (imsg.hdr.len - IMSG_HEADER_SIZE !=
> sizeof(ps->name))
> fatalx("IMSG_RECONF_PREFIXSET bad len");
> @@ -884,9 +892,22 @@ rde_dispatch_imsg_parent(struct imsgbuf
> if (ps == NULL)
> fatal(NULL);
> memcpy(ps->name, imsg.data, sizeof(ps->name));
> - SIMPLEQ_INSERT_TAIL(prefixsets_tmp, ps, entry);
> + if (imsg.hdr.type == IMSG_RECONF_ROA_SET) {
> + SIMPLEQ_INSERT_TAIL(roasets_tmp, ps, entry);
> + ps->roa = 1;
> + last_set = set_new(1, sizeof(struct roa_set));
> + if (last_set == NULL)
> + fatal(NULL);
> + } else
> + SIMPLEQ_INSERT_TAIL(prefixsets_tmp, ps, entry);
> last_prefixset = ps;
> break;
> + case IMSG_RECONF_ROA_AS_SET_ITEMS:
> + nmemb = imsg.hdr.len - IMSG_HEADER_SIZE;
> + nmemb /= sizeof(struct roa_set);
> + if (set_add(last_set, imsg.data, nmemb) != 0)
> + fatal(NULL);
> + break;
> case IMSG_RECONF_PREFIXSETITEM:
> if (imsg.hdr.len - IMSG_HEADER_SIZE !=
> sizeof(psi))
> @@ -894,11 +915,19 @@ rde_dispatch_imsg_parent(struct imsgbuf
> memcpy(&psi, imsg.data, sizeof(psi));
> if (last_prefixset == NULL)
> fatalx("King Bula has no prefixset");
> - if (trie_add(&last_prefixset->th, &psi.p.addr,
> - psi.p.len, psi.p.len_min, psi.p.len_max) == -1)
> - log_warnx("trie_add(%s) %s/%u, %u-%u) failed",
> + if (last_prefixset->roa) {
> + set_prep(last_set);
> + rv = trie_roa_add(&last_prefixset->th,
> + &psi.p.addr, psi.p.len, last_set);
> + } else {
> + rv = trie_add(&last_prefixset->th,
> + &psi.p.addr, psi.p.len,
> + psi.p.len_min, psi.p.len_max);
> + }
> + if (rv == -1)
> + log_warnx("trie_add(%s) %s/%u) failed",
> last_prefixset->name, log_addr(&psi.p.addr),
> - psi.p.len, psi.p.len_min, psi.p.len_max);
> + psi.p.len);
> break;
> case IMSG_RECONF_AS_SET:
> if (imsg.hdr.len - IMSG_HEADER_SIZE !=
> @@ -2795,6 +2824,7 @@ rde_reload_done(void)
> }
>
> prefixsets_old = conf->rde_prefixsets;
> + roasets_old = conf->rde_roasets;
> as_sets_old = conf->as_sets;
>
> memcpy(conf, nconf, sizeof(struct bgpd_config));
> @@ -2802,6 +2832,7 @@ rde_reload_done(void)
> conf->csock = NULL;
> conf->rcsock = NULL;
> conf->prefixsets = NULL;
> + conf->roasets = NULL;
> free(nconf);
> nconf = NULL;
>
> @@ -2826,11 +2857,15 @@ rde_reload_done(void)
> /* XXX WHERE IS THE SYNC ??? */
>
> rde_mark_prefixsets_dirty(prefixsets_old, prefixsets_tmp);
> + rde_mark_prefixsets_dirty(roasets_old, roasets_tmp);
> as_sets_mark_dirty(as_sets_old, as_sets_tmp);
>
> /* swap the prefixsets */
> conf->rde_prefixsets = prefixsets_tmp;
> prefixsets_tmp = NULL;
> + /* the roa-sets */
> + conf->rde_roasets = roasets_tmp;
> + roasets_tmp = NULL;
> /* and the as_sets */
> conf->as_sets = as_sets_tmp;
> as_sets_tmp = NULL;
> @@ -3022,6 +3057,8 @@ rde_softreconfig_done(void)
>
> rde_free_prefixsets(prefixsets_old);
> prefixsets_old = NULL;
> + rde_free_prefixsets(roasets_old);
> + roasets_old = NULL;
> as_sets_free(as_sets_old);
> as_sets_old = NULL;
>
>