Implement code to parse, print and reload roa-set tables.
authorclaudio <claudio@openbsd.org>
Fri, 21 Sep 2018 04:55:27 +0000 (04:55 +0000)
committerclaudio <claudio@openbsd.org>
Fri, 21 Sep 2018 04:55:27 +0000 (04:55 +0000)
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 maxlen 24 source-as 3
}
No support for acting on this data yet.
Put it in deraadt@, OK benno@, input and OK denis@

usr.sbin/bgpd/bgpd.c
usr.sbin/bgpd/bgpd.h
usr.sbin/bgpd/config.c
usr.sbin/bgpd/parse.y
usr.sbin/bgpd/printconf.c
usr.sbin/bgpd/rde.c

index d422fe9..108f636 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bgpd.c,v 1.200 2018/09/20 11:45:59 claudio Exp $ */
+/*     $OpenBSD: bgpd.c,v 1.201 2018/09/21 04:55:27 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -516,6 +516,34 @@ reconfigure(char *conffile, struct bgpd_config *conf, struct peer **peer_l)
                        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 509589b..3f7e61f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bgpd.h,v 1.343 2018/09/20 11:45:59 claudio Exp $ */
+/*     $OpenBSD: bgpd.h,v 1.344 2018/09/21 04:55:27 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -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 b34d7aa..60c2d86 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: config.c,v 1.74 2018/09/20 07:46:39 claudio Exp $ */
+/*     $OpenBSD: config.c,v 1.75 2018/09/21 04:55:27 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
@@ -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 *psh)
                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) {
@@ -225,6 +230,11 @@ merge_config(struct bgpd_config *xconf, struct bgpd_config *conf,
        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);
        xconf->as_sets = conf->as_sets;
index 91b1e47..931fa05 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.y,v 1.355 2018/09/20 11:45:59 claudio Exp $ */
+/*     $OpenBSD: parse.y,v 1.356 2018/09/21 04:55:27 claudio Exp $ */
 
 /*
  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -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_extcommunity *, char *,
 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($1); }
                | 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 (find_prefixset(name, sets) != NULL)  {
+               yyerror("%s \"%s\" already exists", type, name);
+               return NULL;
        }
-       if ((curpset = calloc(1, sizeof(*curpset))) == NULL)
+       if ((pset = calloc(1, sizeof(*pset))) == NULL)
                fatal("prefixset");
-       if (strlcpy(curpset->name, name, sizeof(curpset->name)) >=
-           sizeof(curpset->name)) {
-               yyerror("prefix-set \"%s\" too long: max %zu",
-                   name, sizeof(curpset->name) - 1);
-                       return -1;
+       if (strlcpy(pset->name, name, sizeof(pset->name)) >=
+           sizeof(pset->name)) {
+               yyerror("%s \"%s\" too long: max %zu", type,
+                   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 d4648c1..451a50b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: printconf.c,v 1.121 2018/09/20 11:45:59 claudio Exp $ */
+/*     $OpenBSD: printconf.c,v 1.122 2018/09/21 04:55:27 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -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);
@@ -485,6 +486,35 @@ print_prefixsets(struct prefixset_head *psh)
        }
 }
 
+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)
 {
@@ -891,6 +921,7 @@ print_config(struct bgpd_config *conf, struct rib_names *rib_l,
        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 39ccae7..2308136 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rde.c,v 1.425 2018/09/20 11:45:59 claudio Exp $ */
+/*     $OpenBSD: rde.c,v 1.426 2018/09/21 04:55:27 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -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 *ibuf)
 {
        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 *ibuf)
        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 *ibuf)
                        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 *ibuf)
                                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 *ibuf)
                        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 *ibuf)
                        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;