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;
>  
> 

Reply via email to