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
}

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;
 

Reply via email to