Claudio Jeker(cje...@diehard.n-r-g.com) on 2018.09.27 10:57:12 +0200:
> On Thu, Sep 27, 2018 at 09:39:36AM +0200, Claudio Jeker wrote:
> > On Wed, Sep 26, 2018 at 06:24:36PM +0200, Claudio Jeker wrote:
> > > On Tue, Sep 25, 2018 at 12:23:48PM +0200, Claudio Jeker wrote:
> > > > On Sat, Sep 22, 2018 at 09:48:24PM +0000, Job Snijders wrote:
> > > > > Hi claudio,
> > > > > 
> > > > > Seems we are getting very close. Some suggestions to simplify the
> > > > > experience for the end user.
> > > > > 
> > > > > Let's start with supporting just one (unnamed) roa-set, so far I've
> > > > > really not come across a use case where multiple ROA tables are 
> > > > > useful.
> > > > > I say this having implemented origin validation on both ISPs and IXPs.
> > > > > 
> > > > > The semantics of the Origin Validation procedure that apply to
> > > > > "Validated ROA Payloads" are not compatible with how the ARIN WHOIS
> > > > > OriginAS semantics, so roa-set will never be used for ARIN WHOIS data.
> > > > 
> > > > Please explain further, because honestly both the ruleset that
> > > > arouteserver generates for ARIN WHOIS OriginAS and ROA are doing
> > > > the same. They connect a source-as with a prefix. This is what a
> > > > roa-set is giving you. It implements a way to quickly lookup a 2 key
> > > > element (AS + prefix). Depending on how this table is used it can be 
> > > > used
> > > > for both cases. This is the technical view based on looking at rulesets 
> > > > and
> > > > thinking on how to write them in a way that is fast and understandable.
> > > > I understand that from an administration point of view RPKI ROA is much
> > > > stronger and can therefor be used more strictly (e.g. with the simple 
> > > > rule
> > > > deny quick from ebgp roa-set RPKI invalid). The generic origin 
> > > > validatiation
> > > > as a supporting measure to IRR based prefixset filtering is only 
> > > > allowing
> > > > additional prefixes based on the roa-set (e.g. match from ebgp \
> > > > large-community $INTCOMM_ORIGIN_OK roa-set ARINDB valid \
> > > > set large-community $INTCOMM_PREF_OK). They are two different things but
> > > > can use the same filter building blocks.
> > > > Maybe naming it roa-set is wrong (since it is too much connected with
> > > > RPKI) but the lookup table is usable for more than just RPKI. This is 
> > > > why
> > > > I think supporting multiple tables is benefitial. I also agree that a
> > > > simplified user experience for RPKI is a good thing, it should be simple
> > > > to use.
> > > > 
> > > > > There currently is 1 RPKI, and therefor we should have just 1 roa-set.
> > > > 
> > > > I would fully agree here if ARIN would make their trust anchor freely
> > > > distributable. But yes in general only one RPKI table is needed.
> > > > My point is that roa-set is more generic than RPKI. It is not an RPKI 
> > > > only
> > > > thing. It can be used for more than that and we should support this as
> > > > well since it makes for much better and efficient configs.
> > > >  
> > > > > The advantage of having only one roa-set is that it does not need to 
> > > > > be
> > > > > referenced in the policies.
> > > > > 
> > > > > I propose the patch is amended to accomodate the following:
> > > > > 
> > > > >       roa-set {
> > > > >               165.254.255.0/24 source-as 15562
> > > > >               193.0.0.0/21 source-as 3333
> > > > >       }
> > > > > 
> > > > >       deny from any ovs invalid
> > > > >       match from any ovs valid set community local-as:42
> > > > >       match from any ovs unknown set community local-as:43
> > > > > 
> > > > > I suggest the filter keyword 'ovs' (origin validation state) is
> > > > > introduced to allow easy matching. I think this looks better. If the
> > > > > roa-set is not defined or empty, all route announcements are 
> > > > > 'unknown'.
> > > > 
> > > > If we want to use ovs then the naming scheme should be the same as for 
> > > > the
> > > > extended community. At least if we reuse this keyword it should work the
> > > > same. Also the side-effect is that the two configs look fairly similar
> > > > which can be good or bad:
> > > > match from any ovs valid set community local-as:42 
> > > > match from any ext-community ovs valid set community local-as:42 
> > > > 
> > > > I'm not against this, just wanted to bring it up.
> > > > 
> > > > Also I think unknown should be renamed not-found. I will do that since
> > > > not-found is what the RFC is using.
> > > > 
> > > > I will rework the diff considering the input.
> > > 
> > > Here we go. This changes the diff so there is only one roa-set like
> > > mentioned above:
> > > 
> > >   roa-set {
> > >           165.254.255.0/24 source-as 15562
> > >           193.0.0.0/21 source-as 3333
> > >   }
> > >  
> > >   deny from any ovs invalid
> > >   match from any ovs valid set community local-as:42
> > >   match from any ovs unknown set community local-as:43
> > > 
> > > Additionally I left the old sets around but used a bit different:
> > > 
> > >   origin-set FOO {
> > >           ...
> > >   }
> > > 
> > >   match from any community $ORIGIN_AS_OK origin-set FOO valid \
> > >           set community $ORIGIN_PREF_OK
> > > 
> > > I may even consider to drop the 'valid' in the above rule since that is
> > > the only check that kind of matters in this case.
> > > 
> > 
> > New version removing the validity argument from origin-set FOO filter
> > rules as mentioned above. Apart from that it should be the same.
> > 
> 
> And the moment I sent this benno@ reported that I forgot to fixup 'set
> ext-community ovs' in parse.y since ovs is now a keyword. Adjusted patch
> below.

I'm still unsure about the origin-sets. However i dont think they hurt: even
if they are in 6.4, if we later want to change things in this regard, we
still can do that.

ok benno@


> Index: bgpd.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
> retrieving revision 1.202
> diff -u -p -r1.202 bgpd.c
> --- bgpd.c    25 Sep 2018 07:58:11 -0000      1.202
> +++ bgpd.c    26 Sep 2018 10:34:53 -0000
> @@ -506,15 +506,15 @@ reconfigure(char *conffile, struct bgpd_
>               return (-1);
>  
>       /* prefixsets for filters in the RDE */
> -     while ((ps = SIMPLEQ_FIRST(conf->prefixsets)) != NULL) {
> -             SIMPLEQ_REMOVE_HEAD(conf->prefixsets, entry);
> -             if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSET, 0, 0, -1,
> +     while ((ps = SIMPLEQ_FIRST(&conf->prefixsets)) != NULL) {
> +             SIMPLEQ_REMOVE_HEAD(&conf->prefixsets, entry);
> +             if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET, 0, 0, -1,
>                   ps->name, sizeof(ps->name)) == -1)
>                       return (-1);
>               RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) {
>                       RB_REMOVE(prefixset_tree, &ps->psitems, psi);
> -                     if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSETITEM, 0,
> -                         0, -1, psi, sizeof(*psi)) == -1)
> +                     if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET_ITEM,
> +                         0, 0, -1, psi, sizeof(*psi)) == -1)
>                               return (-1);
>                       set_free(psi->set);
>                       free(psi);
> @@ -522,10 +522,10 @@ reconfigure(char *conffile, struct bgpd_
>               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,
> +     /* originsets for filters in the RDE */
> +     while ((ps = SIMPLEQ_FIRST(&conf->originsets)) != NULL) {
> +             SIMPLEQ_REMOVE_HEAD(&conf->originsets, entry);
> +             if (imsg_compose(ibuf_rde, IMSG_RECONF_ORIGIN_SET, 0, 0, -1,
>                   ps->name, sizeof(ps->name)) == -1)
>                       return (-1);
>               RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) {
> @@ -536,17 +536,41 @@ reconfigure(char *conffile, struct bgpd_
>                       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,
> +                                 IMSG_RECONF_ROA_SET_ITEMS,
>                                   0, 0, -1, rs + i, l * sizeof(*rs)) == -1)
>                                       return -1;
>                       }
> -                     if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSETITEM, 0,
> -                         0, -1, psi, sizeof(*psi)) == -1)
> +                     if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET_ITEM,
> +                         0, 0, -1, psi, sizeof(*psi)) == -1)
>                               return (-1);
>                       set_free(psi->set);
>                       free(psi);
>               }
>               free(ps);
> +     }
> +
> +     if (!RB_EMPTY(&conf->roa)) {
> +             if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_SET, 0, 0, -1,
> +                 NULL, 0) == -1)
> +                     return (-1);
> +             RB_FOREACH_SAFE(psi, prefixset_tree, &conf->roa, npsi) {
> +                     struct roa_set *rs;
> +                     size_t i, l, n;
> +                     RB_REMOVE(prefixset_tree, &conf->roa, psi);
> +                     rs = 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_SET_ITEMS,
> +                                 0, 0, -1, rs + i, l * sizeof(*rs)) == -1)
> +                                     return -1;
> +                     }
> +                     if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIX_SET_ITEM,
> +                         0, 0, -1, psi, sizeof(*psi)) == -1)
> +                             return (-1);
> +                     set_free(psi->set);
> +                     free(psi);
> +             }
>       }
>  
>       /* as-sets for filters in the RDE */
> Index: bgpd.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
> retrieving revision 1.345
> diff -u -p -r1.345 bgpd.h
> --- bgpd.h    26 Sep 2018 15:48:01 -0000      1.345
> +++ bgpd.h    27 Sep 2018 07:03:12 -0000
> @@ -212,8 +212,25 @@ TAILQ_HEAD(network_head, network);
>  
>  struct prefixset;
>  SIMPLEQ_HEAD(prefixset_head, prefixset);
> -struct rde_prefixset_head;
> -struct rde_prefixset;
> +struct prefixset_item;
> +RB_HEAD(prefixset_tree, prefixset_item);
> +
> +struct tentry_v4;
> +struct tentry_v6;
> +struct trie_head {
> +     struct tentry_v4        *root_v4;
> +     struct tentry_v6        *root_v6;
> +     int                      match_default_v4;
> +     int                      match_default_v6;
> +};
> +
> +struct rde_prefixset {
> +     char                            name[SET_NAME_LEN];
> +     struct trie_head                th;
> +     SIMPLEQ_ENTRY(rde_prefixset)    entry;
> +     int                             dirty;
> +};
> +SIMPLEQ_HEAD(rde_prefixset_head, rde_prefixset);
>  
>  struct set_table;
>  struct as_set;
> @@ -228,10 +245,12 @@ struct bgpd_config {
>       struct filter_head                      *filters;
>       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 prefixset_head                    prefixsets;
> +     struct prefixset_head                    originsets;
> +     struct prefixset_tree                    roa;
> +     struct rde_prefixset_head                rde_prefixsets;
> +     struct rde_prefixset_head                rde_originsets;
> +     struct rde_prefixset                     rde_roa;
>       struct as_set_head                      *as_sets;
>       char                                    *csock;
>       char                                    *rcsock;
> @@ -428,13 +447,14 @@ enum imsg_type {
>       IMSG_RECONF_RDOMAIN_EXPORT,
>       IMSG_RECONF_RDOMAIN_IMPORT,
>       IMSG_RECONF_RDOMAIN_DONE,
> -     IMSG_RECONF_PREFIXSET,
> -     IMSG_RECONF_PREFIXSETITEM,
> +     IMSG_RECONF_PREFIX_SET,
> +     IMSG_RECONF_PREFIX_SET_ITEM,
>       IMSG_RECONF_AS_SET,
>       IMSG_RECONF_AS_SET_ITEMS,
>       IMSG_RECONF_AS_SET_DONE,
> +     IMSG_RECONF_ORIGIN_SET,
>       IMSG_RECONF_ROA_SET,
> -     IMSG_RECONF_ROA_AS_SET_ITEMS,
> +     IMSG_RECONF_ROA_SET_ITEMS,
>       IMSG_RECONF_DONE,
>       IMSG_UPDATE,
>       IMSG_UPDATE_ERR,
> @@ -695,6 +715,16 @@ struct filter_prefixset {
>       struct rde_prefixset    *ps;
>  };
>  
> +struct filter_originset {
> +     char                     name[SET_NAME_LEN];
> +     struct rde_prefixset    *ps;
> +};
> +
> +struct filter_ovs {
> +     u_int8_t                 validity;
> +     u_int8_t                 is_set;
> +};
> +
>  struct filter_community {
>       int             as;
>       int             type;
> @@ -886,6 +916,8 @@ struct filter_match {
>       struct filter_largecommunity    large_community;
>       struct filter_extcommunity      ext_community;
>       struct filter_prefixset         prefixset;
> +     struct filter_originset         originset;
> +     struct filter_ovs               ovs;
>  };
>  
>  union filter_rule_ptr {
> @@ -967,7 +999,6 @@ struct prefixset_item {
>       RB_ENTRY(prefixset_item)        entry;
>       struct set_table                *set;
>  };
> -RB_HEAD(prefixset_tree, prefixset_item);
>  
>  struct prefixset {
>       int                              sflags;
> @@ -1015,6 +1046,8 @@ extern struct rib_names ribnames;
>  
>  /* 4-byte magic AS number */
>  #define AS_TRANS     23456
> +/* AS_NONE for origin validation */
> +#define AS_NONE              0
>  
>  struct rde_memstats {
>       int64_t         path_cnt;
> @@ -1099,6 +1132,7 @@ int     control_imsg_relay(struct imsg *);
>  struct bgpd_config   *new_config(void);
>  void                  free_config(struct bgpd_config *);
>  void free_prefixsets(struct prefixset_head *);
> +void free_prefixtree(struct prefixset_tree *);
>  void filterlist_free(struct filter_head *);
>  int  host(const char *, struct bgpd_addr *, u_int8_t *);
>  void copy_filterset(struct filter_set_head *, struct filter_set_head *);
> Index: config.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/config.c,v
> retrieving revision 1.76
> diff -u -p -r1.76 config.c
> --- config.c  21 Sep 2018 20:45:50 -0000      1.76
> +++ config.c  26 Sep 2018 14:15:49 -0000
> @@ -63,11 +63,6 @@ new_config(void)
>           conf->default_tableid) == -1)
>               fatal(NULL);
>  
> -     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,8 +76,9 @@ new_config(void)
>       /* init the various list for later */
>       TAILQ_INIT(&conf->networks);
>       SIMPLEQ_INIT(&conf->rdomains);
> -     SIMPLEQ_INIT(conf->prefixsets);
> -     SIMPLEQ_INIT(conf->roasets);
> +     SIMPLEQ_INIT(&conf->prefixsets);
> +     SIMPLEQ_INIT(&conf->originsets);
> +     RB_INIT(&conf->roa);
>       SIMPLEQ_INIT(conf->as_sets);
>  
>       TAILQ_INIT(conf->filters);
> @@ -122,22 +118,25 @@ void
>  free_prefixsets(struct prefixset_head *psh)
>  {
>       struct prefixset        *ps;
> -     struct prefixset_item   *psi, *npsi;
> -
> -     if (psh == NULL)
> -             return;
>  
>       while (!SIMPLEQ_EMPTY(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);
> -             }
> +             free_prefixtree(&ps->psitems);
>               SIMPLEQ_REMOVE_HEAD(psh, entry);
>               free(ps);
>       }
> -     free(psh);
> +}
> +
> +void
> +free_prefixtree(struct prefixset_tree *p)
> +{
> +     struct prefixset_item   *psi, *npsi;
> +
> +     RB_FOREACH_SAFE(psi, prefixset_tree, p, npsi) {
> +             RB_REMOVE(prefixset_tree, p, psi);
> +             set_free(psi->set);
> +             free(psi);
> +     }
>  }
>  
>  void
> @@ -149,8 +148,9 @@ free_config(struct bgpd_config *conf)
>       free_rdomains(&conf->rdomains);
>       free_networks(&conf->networks);
>       filterlist_free(conf->filters);
> -     free_prefixsets(conf->prefixsets);
> -     free_prefixsets(conf->roasets);
> +     free_prefixsets(&conf->prefixsets);
> +     free_prefixsets(&conf->originsets);
> +     free_prefixtree(&conf->roa);
>       as_sets_free(conf->as_sets);
>  
>       while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
> @@ -224,15 +224,19 @@ merge_config(struct bgpd_config *xconf, 
>       xconf->filters = conf->filters;
>       conf->filters = NULL;
>  
> +     /* switch the roa, first remove the old one */
> +     free_prefixtree(&xconf->roa);
> +     /* then move the RB tree root */
> +     RB_ROOT(&xconf->roa) = RB_ROOT(&conf->roa);
> +     RB_ROOT(&conf->roa) = NULL;
> +
>       /* switch the prefixsets, first remove the old ones */
> -     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;
> +     free_prefixsets(&xconf->prefixsets);
> +     SIMPLEQ_CONCAT(&xconf->prefixsets, &conf->prefixsets);
> +
> +     /* switch the originsets, first remove the old ones */
> +     free_prefixsets(&xconf->originsets);
> +     SIMPLEQ_CONCAT(&xconf->originsets, &conf->originsets);
>  
>       /* switch the as_sets, first remove the old ones */
>       as_sets_free(xconf->as_sets);
> @@ -511,7 +515,7 @@ expand_networks(struct bgpd_config *c)
>       TAILQ_FOREACH_SAFE(n, nw, entry, tmp) {
>               if (n->net.type == NETWORK_PREFIXSET) {
>                       TAILQ_REMOVE(nw, n, entry);
> -                     if ((ps = find_prefixset(n->net.psname, c->prefixsets))
> +                     if ((ps = find_prefixset(n->net.psname, &c->prefixsets))
>                           == NULL)
>                               fatal("%s: prefixset %s not found", __func__,
>                                   n->net.psname);
> Index: parse.y
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
> retrieving revision 1.359
> diff -u -p -r1.359 parse.y
> --- parse.y   21 Sep 2018 08:17:15 -0000      1.359
> +++ parse.y   27 Sep 2018 08:46:26 -0000
> @@ -92,8 +92,8 @@ static struct peer          *peer_l, *peer_l_old
>  static struct peer           *curpeer;
>  static struct peer           *curgroup;
>  static struct rdomain                *currdom;
> -static struct prefixset              *curpset;
> -static struct prefixset              *curroaset;
> +static struct prefixset              *curpset, *curoset;
> +static struct prefixset_tree *curpsitree;
>  static struct filter_head    *filter_l;
>  static struct filter_head    *peerfilter_l;
>  static struct filter_head    *groupfilter_l;
> @@ -213,7 +213,8 @@ typedef struct {
>  %token       FROM TO ANY
>  %token       CONNECTED STATIC
>  %token       COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE
> -%token       PREFIX PREFIXLEN PREFIXSET ROASET
> +%token       PREFIX PREFIXLEN PREFIXSET
> +%token       ROASET ORIGINSET OVS
>  %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
> @@ -226,7 +227,7 @@ typedef struct {
>  %token       <v.number>              NUMBER
>  %type        <v.number>              asnumber as4number as4number_any 
> optnumber
>  %type        <v.number>              espah family restart origincode nettype
> -%type        <v.number>              yesno inout restricted
> +%type        <v.number>              yesno inout restricted validity
>  %type        <v.string>              string
>  %type        <v.addr>                address
>  %type        <v.prefix>              prefix addrspec
> @@ -253,6 +254,7 @@ grammar           : /* empty */
>               | grammar as_set '\n'
>               | grammar prefixset '\n'
>               | grammar roa_set '\n'
> +             | grammar origin_set '\n'
>               | grammar conf_main '\n'
>               | grammar rdomain '\n'
>               | grammar neighbor '\n'
> @@ -432,7 +434,7 @@ prefixset : PREFIXSET STRING '{' optnl            
>                       }
>                       free($2);
>               } prefixset_l optnl '}'                 {
> -                     SIMPLEQ_INSERT_TAIL(conf->prefixsets, curpset, entry);
> +                     SIMPLEQ_INSERT_TAIL(&conf->prefixsets, curpset, entry);
>                       curpset = NULL;
>               }
>               | PREFIXSET STRING '{' optnl '}'        {
> @@ -441,7 +443,7 @@ prefixset : PREFIXSET STRING '{' optnl            
>                               YYERROR;
>                       }
>                       free($2);
> -                     SIMPLEQ_INSERT_TAIL(conf->prefixsets, curpset, entry);
> +                     SIMPLEQ_INSERT_TAIL(&conf->prefixsets, curpset, entry);
>                       curpset = NULL;
>               }
>  
> @@ -492,24 +494,35 @@ prefixset_item  : prefix prefixlenop                    
> {
>               }
>               ;
>  
> -roa_set              : ROASET STRING '{' optnl               {
> -                     if ((curroaset = new_prefix_set($2, 1)) == NULL) {
> +roa_set              : ROASET '{' optnl              {
> +                     curpsitree = &conf->roa;
> +             } roa_set_l optnl '}'                   {
> +                     curpsitree = NULL;
> +             }
> +             | ROASET '{' optnl '}'          /* nothing */
> +             ;
> +
> +origin_set   : ORIGINSET STRING '{' optnl            {
> +                     if ((curoset = new_prefix_set($2, 1)) == NULL) {
>                               free($2);
>                               YYERROR;
>                       }
> +                     curpsitree = &curoset->psitems;
>                       free($2);
>               } roa_set_l optnl '}'                   {
> -                     SIMPLEQ_INSERT_TAIL(conf->roasets, curroaset, entry);
> -                     curroaset = NULL;
> +                     SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry);
> +                     curoset = NULL;
> +                     curpsitree = NULL;
>               }
> -             | ROASET STRING '{' optnl '}'           {
> -                     if ((curroaset = new_prefix_set($2, 1)) == NULL) {
> +             | ORIGINSET STRING '{' optnl '}'                {
> +                     if ((curoset = new_prefix_set($2, 1)) == NULL) {
>                               free($2);
>                               YYERROR;
>                       }
>                       free($2);
> -                     SIMPLEQ_INSERT_TAIL(conf->roasets, curroaset, entry);
> -                     curroaset = NULL;
> +                     SIMPLEQ_INSERT_TAIL(&conf->originsets, curoset, entry);
> +                     curoset = NULL;
> +                     curpsitree = NULL;
>               }
>               ;
>  
> @@ -864,7 +877,7 @@ network           : NETWORK prefix filter_set     {
>               | NETWORK PREFIXSET STRING filter_set   {
>                       struct prefixset *ps;
>                       struct network  *n;
> -                     if ((ps = find_prefixset($3, conf->prefixsets))
> +                     if ((ps = find_prefixset($3, &conf->prefixsets))
>                           == NULL) {
>                               yyerror("prefix-set %s not defined", ps->name);
>                               free($3);
> @@ -2169,6 +2182,21 @@ filter_elm     : filter_prefix_h       {
>                       free($2);
>                       free($3);
>               }
> +             | EXTCOMMUNITY OVS STRING {
> +                     if (fmopts.m.ext_community.flags &
> +                         EXT_COMMUNITY_FLAG_VALID) {
> +                             yyerror("\"ext-community\" already specified");
> +                             free($3);
> +                             YYERROR;
> +                     }
> +
> +                     if (parseextcommunity(&fmopts.m.ext_community,
> +                         "ovs", $3) == -1) {
> +                             free($3);
> +                             YYERROR;
> +                     }
> +                     free($3);
> +             }
>               | NEXTHOP address       {
>                       if (fmopts.m.nexthop.flags) {
>                               yyerror("nexthop already specified");
> @@ -2198,9 +2226,9 @@ filter_elm      : filter_prefix_h       {
>                               free($2);
>                               YYERROR;
>                       }
> -                     if ((ps = find_prefixset($2, conf->prefixsets))
> +                     if ((ps = find_prefixset($2, &conf->prefixsets))
>                           == NULL) {
> -                             yyerror("prefix-set not defined");
> +                             yyerror("prefix-set '%s' not defined", $2);
>                               free($2);
>                               YYERROR;
>                       }
> @@ -2222,7 +2250,7 @@ filter_elm      : filter_prefix_h       {
>                       if ($3.op == OP_RANGE && ps->sflags & 
> PREFIXSET_FLAG_OPS) {
>                               yyerror("prefix-set %s contains prefixlen "
>                                   "operators and cannot be used with an "
> -                                 "or-longer filter", ps->name);
> +                                 "or-longer filter", $2);
>                               free($2);
>                               YYERROR;
>                       }
> @@ -2231,9 +2259,36 @@ filter_elm     : filter_prefix_h       {
>                               fmopts.m.prefixset.flags |=
>                                   PREFIXSET_FLAG_LONGER;
>                       fmopts.m.prefixset.flags |= PREFIXSET_FLAG_FILTER;
> -                     fmopts.m.prefixset.ps = NULL;
>                       free($2);
>               }
> +             | ORIGINSET STRING {
> +                     if (fmopts.m.originset.name[0] != '\0') {
> +                             yyerror("origin-set filter already specified");
> +                             free($2);
> +                             YYERROR;
> +                     }
> +                     if (find_prefixset($2, &conf->originsets) == NULL) {
> +                             yyerror("origin-set '%s' not defined", $2);
> +                             free($2);
> +                             YYERROR;
> +                     }
> +                     if (strlcpy(fmopts.m.originset.name, $2,
> +                         sizeof(fmopts.m.originset.name)) >=
> +                         sizeof(fmopts.m.originset.name)) {
> +                             yyerror("origin-set name too long");
> +                             free($2);
> +                             YYERROR;
> +                     }
> +                     free($2);
> +             }
> +             | OVS validity          {
> +                     if (fmopts.m.ovs.is_set) {
> +                             yyerror("ovs filter already specified");
> +                             YYERROR;
> +                     }
> +                     fmopts.m.ovs.validity = $2;
> +                     fmopts.m.ovs.is_set = 1;
> +             }
>               ;
>  
>  prefixlenop  : /* empty */                   { bzero(&$$, sizeof($$)); }
> @@ -2641,6 +2696,22 @@ filter_set_opt : LOCALPREF NUMBER              {
>                       free($3);
>                       free($4);
>               }
> +             | EXTCOMMUNITY delete OVS STRING {
> +                     if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
> +                             fatal(NULL);
> +                     if ($2)
> +                             $$->type = ACTION_DEL_EXT_COMMUNITY;
> +                     else
> +                             $$->type = ACTION_SET_EXT_COMMUNITY;
> +
> +                     if (parseextcommunity(&$$->action.ext_community,
> +                         "ovs", $4) == -1) {
> +                             free($4);
> +                             free($$);
> +                             YYERROR;
> +                     }
> +                     free($4);
> +             }
>               | ORIGIN origincode {
>                       if (($$ = calloc(1, sizeof(struct filter_set))) == NULL)
>                               fatal(NULL);
> @@ -2649,7 +2720,7 @@ filter_set_opt  : LOCALPREF NUMBER              {
>               }
>               ;
>  
> -origincode   : string {
> +origincode   : STRING        {
>                       if (!strcmp($1, "egp"))
>                               $$ = ORIGIN_EGP;
>                       else if (!strcmp($1, "igp"))
> @@ -2664,6 +2735,21 @@ origincode     : string {
>                       free($1);
>               };
>  
> +validity     : STRING        {
> +                     if (!strcmp($1, "not-found"))
> +                             $$ = ROA_NOTFOUND;
> +                     else if (!strcmp($1, "invalid"))
> +                             $$ = ROA_INVALID;
> +                     else if (!strcmp($1, "valid"))
> +                             $$ = ROA_VALID;
> +                     else {
> +                             yyerror("unknown validity \"%s\"", $1);
> +                             free($1);
> +                             YYERROR;
> +                     }
> +                     free($1);
> +             };
> +
>  optnl                : /* empty */
>               | '\n' optnl
>               ;
> @@ -2792,7 +2878,9 @@ lookup(char *s)
>               { "on",                 ON},
>               { "or-longer",          LONGER},
>               { "origin",             ORIGIN},
> +             { "origin-set",         ORIGINSET},
>               { "out",                OUT},
> +             { "ovs",                OVS},
>               { "passive",            PASSIVE},
>               { "password",           PASSWORD},
>               { "peer-as",            PEERAS},
> @@ -4281,12 +4369,12 @@ static struct prefixset *
>  new_prefix_set(char *name, int is_roa)
>  {
>       const char *type = "prefix-set";
> -     struct prefixset_head *sets = conf->prefixsets;
> +     struct prefixset_head *sets = &conf->prefixsets;
>       struct prefixset *pset;
>  
>       if (is_roa) {
>               type = "roa-set";
> -             sets = conf->roasets;
> +             sets = &conf->originsets;
>       }
>  
>       if (find_prefixset(name, sets) != NULL)  {
> @@ -4315,7 +4403,7 @@ add_roa_set(struct prefixset_item *npsi,
>       /* no prefixlen option in this tree */
>       npsi->p.op = OP_NONE;
>       npsi->p.len_max = npsi->p.len_min = npsi->p.len;
> -     psi = RB_INSERT(prefixset_tree, &curroaset->psitems, npsi);
> +     psi = RB_INSERT(prefixset_tree, curpsitree, npsi);
>       if (psi == NULL)
>               psi = npsi;
>  
> Index: printconf.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
> retrieving revision 1.122
> diff -u -p -r1.122 printconf.c
> --- printconf.c       21 Sep 2018 04:55:27 -0000      1.122
> +++ printconf.c       27 Sep 2018 08:44:46 -0000
> @@ -42,7 +42,8 @@ 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_originsets(struct prefixset_head *);
> +void          print_roa(struct prefixset_tree *p);
>  void          print_peer(struct peer_config *, struct bgpd_config *,
>                   const char *);
>  const char   *print_auth_alg(u_int8_t);
> @@ -86,11 +87,11 @@ print_prefix(struct filter_prefix *p)
>               printf(" prefixlen %u >< %u ", p->len_min, p->len_max);
>               break;
>       case OP_RANGE:
> -             if (p->len_min == p->len_max)
> +             if (p->len_min == p->len_max && p->len != p->len_min)
>                       printf(" prefixlen = %u", p->len_min);
>               else if (p->len == p->len_min && p->len_max == max_len)
>                       printf(" or-longer");
> -             else if (p->len == p->len_min)
> +             else if (p->len == p->len_min && p->len != p->len_max)
>                       printf(" maxlen %u", p->len_max);
>               else if (p->len_max == max_len)
>                       printf(" prefixlen >= %u", p->len_min);
> @@ -487,7 +488,7 @@ print_prefixsets(struct prefixset_head *
>  }
>  
>  void
> -print_roasets(struct prefixset_head *psh)
> +print_originsets(struct prefixset_head *psh)
>  {
>       struct prefixset        *ps;
>       struct prefixset_item   *psi;
> @@ -495,16 +496,11 @@ print_roasets(struct prefixset_head *psh
>       size_t                   i, n;
>  
>       SIMPLEQ_FOREACH(ps, psh, entry) {
> -             int count = 0;
> -             printf("roa-set \"%s\" {", ps->name);
> +             printf("origin-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(", ");
> -
> +                             printf("\n\t");
>                               print_prefix(&psi->p);
>                               if (psi->p.len != rs[i].maxlen)
>                                       printf(" maxlen %u", rs[i].maxlen);
> @@ -516,6 +512,30 @@ print_roasets(struct prefixset_head *psh
>  }
>  
>  void
> +print_roa(struct prefixset_tree *p)
> +{
> +     struct prefixset_item   *psi;
> +     struct roa_set          *rs;
> +     size_t                   i, n;
> +
> +     if (RB_EMPTY(p))
> +             return;
> +
> +     printf("roa-set {");
> +     RB_FOREACH(psi, prefixset_tree, p) {
> +             rs = set_get(psi->set, &n);
> +             for (i = 0; i < n; i++) {
> +                     printf("\n\t");
> +                     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;
> @@ -741,17 +761,36 @@ print_rule(struct peer *peer_l, struct f
>       } else
>               printf("any ");
>  
> +     if (r->match.ovs.is_set) {
> +             switch (r->match.ovs.validity) {
> +             case ROA_VALID:
> +                     printf("ovs valid ");
> +                     break;
> +             case ROA_INVALID:
> +                     printf("ovs invalid ");
> +                     break;
> +             case ROA_NOTFOUND:
> +                     printf("ovs not-found ");
> +                     break;
> +             default:
> +                     printf("ovs ??? %d ??? ", r->match.ovs.validity);
> +             }
> +     }
> +
>       if (r->match.prefix.addr.aid != AID_UNSPEC) {
>               printf("prefix ");
>               print_prefix(&r->match.prefix);
>               printf(" ");
>       }
>  
> -     if (r->match.prefixset.flags & PREFIXSET_FLAG_FILTER)
> +     if (r->match.prefixset.name[0] != '\0')
>               printf("prefix-set \"%s\" ", r->match.prefixset.name);
>       if (r->match.prefixset.flags & PREFIXSET_FLAG_LONGER)
>               printf("or-longer ");
>  
> +     if (r->match.originset.name[0] != '\0')
> +             printf("origin-set \"%s\" ", r->match.originset.name);
> +
>       if (r->match.nexthop.flags) {
>               if (r->match.nexthop.flags == FILTER_NEXTHOP_NEIGHBOR)
>                       printf("nexthop neighbor ");
> @@ -919,9 +958,10 @@ print_config(struct bgpd_config *conf, s
>       struct rdomain          *rd;
>  
>       print_mainconf(conf);
> -     print_prefixsets(conf->prefixsets);
> +     print_roa(&conf->roa);
>       print_as_sets(conf->as_sets);
> -     print_roasets(conf->roasets);
> +     print_prefixsets(&conf->prefixsets);
> +     print_originsets(&conf->originsets);
>       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.427
> diff -u -p -r1.427 rde.c
> --- rde.c     25 Sep 2018 08:08:38 -0000      1.427
> +++ rde.c     26 Sep 2018 16:13:52 -0000
> @@ -103,7 +103,9 @@ void               rde_update6_queue_runner(u_int8_t
>  struct rde_prefixset *rde_find_prefixset(char *, struct rde_prefixset_head 
> *);
>  void          rde_free_prefixsets(struct rde_prefixset_head *);
>  void          rde_mark_prefixsets_dirty(struct rde_prefixset_head *,
> -                     struct rde_prefixset_head *);
> +                  struct rde_prefixset_head *);
> +u_int8_t      rde_roa_validity(struct rde_prefixset *,
> +                  struct bgpd_addr *, u_int8_t, u_int32_t);
>  
>  void          peer_init(u_int32_t);
>  void          peer_shutdown(void);
> @@ -130,8 +132,9 @@ struct bgpd_config        *conf, *nconf;
>  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 rde_prefixset_head prefixsets_old;
> +struct rde_prefixset_head originsets_old;
> +struct rde_prefixset  roa_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;
> @@ -500,6 +503,7 @@ rde_dispatch_imsg_session(struct imsgbuf
>                       asp->origin = csr.origin;
>                       asp->flags |= F_PREFIX_ANNOUNCED | F_ANN_DYNAMIC;
>                       asp->aspath = aspath_get(asdata, csr.aspath_len);
> +                     asp->source_as = aspath_origin(asp->aspath);
>                       netconf_s.asp = asp;
>                       break;
>               case IMSG_NETWORK_ATTR:
> @@ -771,16 +775,6 @@ rde_dispatch_imsg_parent(struct imsgbuf 
>                           sizeof(struct bgpd_config))
>                               fatalx("IMSG_RECONF_CONF bad len");
>                       reloadtime = time(NULL);
> -                     prefixsets_tmp = calloc(1,
> -                         sizeof(struct rde_prefixset_head));
> -                     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)
> @@ -803,6 +797,9 @@ rde_dispatch_imsg_parent(struct imsgbuf 
>                                       break;
>                               ribs[rid].state = RECONF_DELETE;
>                       }
> +                     SIMPLEQ_INIT(&nconf->rde_prefixsets);
> +                     SIMPLEQ_INIT(&nconf->rde_originsets);
> +                     memset(&nconf->rde_roa, 0, sizeof(nconf->rde_roa));
>                       break;
>               case IMSG_RECONF_RIB:
>                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
> @@ -838,14 +835,22 @@ rde_dispatch_imsg_parent(struct imsgbuf 
>                       if ((r = malloc(sizeof(struct filter_rule))) == NULL)
>                               fatal(NULL);
>                       memcpy(r, imsg.data, sizeof(struct filter_rule));
> -                     if (r->match.prefixset.flags != 0) {
> +                     if (r->match.prefixset.name[0] != '\0') {
>                               r->match.prefixset.ps =
>                                   rde_find_prefixset(r->match.prefixset.name,
> -                                     prefixsets_tmp);
> +                                     &nconf->rde_prefixsets);
>                               if (r->match.prefixset.ps == NULL)
>                                       log_warnx("%s: no prefixset for %s",
>                                           __func__, r->match.prefixset.name);
>                       }
> +                     if (r->match.originset.name[0] != '\0') {
> +                             r->match.originset.ps =
> +                                 rde_find_prefixset(r->match.originset.name,
> +                                     &nconf->rde_originsets);
> +                             if (r->match.originset.ps == NULL)
> +                                     log_warnx("%s: no origin-set for %s",
> +                                         __func__, r->match.originset.name);
> +                     }
>                       if (r->match.as.flags & AS_FLAG_AS_SET_NAME) {
>                               struct as_set * aset;
>  
> @@ -883,24 +888,32 @@ rde_dispatch_imsg_parent(struct imsgbuf 
>                       } else
>                               TAILQ_INSERT_TAIL(out_rules_tmp, r, entry);
>                       break;
> -             case IMSG_RECONF_PREFIXSET:
> -             case IMSG_RECONF_ROA_SET:
> +             case IMSG_RECONF_PREFIX_SET:
> +             case IMSG_RECONF_ORIGIN_SET:
>                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
>                           sizeof(ps->name))
> -                             fatalx("IMSG_RECONF_PREFIXSET bad len");
> +                             fatalx("IMSG_RECONF_PREFIX_SET bad len");
>                       ps = calloc(1, sizeof(struct rde_prefixset));
>                       if (ps == NULL)
>                               fatal(NULL);
>                       memcpy(ps->name, imsg.data, sizeof(ps->name));
> -                     if (imsg.hdr.type == IMSG_RECONF_ROA_SET) {
> -                             SIMPLEQ_INSERT_TAIL(roasets_tmp, ps, entry);
> -                             ps->roa = 1;
> -                     } else
> -                             SIMPLEQ_INSERT_TAIL(prefixsets_tmp, ps, entry);
> +                     if (imsg.hdr.type == IMSG_RECONF_ORIGIN_SET) {
> +                             SIMPLEQ_INSERT_TAIL(&nconf->rde_originsets, ps,
> +                                 entry);
> +                     } else {
> +                             SIMPLEQ_INSERT_TAIL(&nconf->rde_prefixsets, ps,
> +                                 entry);
> +                     }
>                       last_prefixset = ps;
>                       last_set = NULL;
>                       break;
> -             case IMSG_RECONF_ROA_AS_SET_ITEMS:
> +             case IMSG_RECONF_ROA_SET:
> +                     strlcpy(nconf->rde_roa.name, "RPKI ROA",
> +                         sizeof(nconf->rde_roa.name));
> +                     last_prefixset = &nconf->rde_roa;
> +                     last_set = NULL;
> +                     break;
> +             case IMSG_RECONF_ROA_SET_ITEMS:
>                       nmemb = imsg.hdr.len - IMSG_HEADER_SIZE;
>                       nmemb /= sizeof(struct roa_set);
>                       if (last_set == NULL) {
> @@ -911,14 +924,14 @@ rde_dispatch_imsg_parent(struct imsgbuf 
>                       if (set_add(last_set, imsg.data, nmemb) != 0)
>                               fatal(NULL);
>                       break;
> -             case IMSG_RECONF_PREFIXSETITEM:
> +             case IMSG_RECONF_PREFIX_SET_ITEM:
>                       if (imsg.hdr.len - IMSG_HEADER_SIZE !=
>                           sizeof(psi))
> -                             fatalx("IMSG_RECONF_PREFIXSETITEM bad len");
> +                             fatalx("IMSG_RECONF_PREFIX_SET_ITEM bad len");
>                       memcpy(&psi, imsg.data, sizeof(psi));
>                       if (last_prefixset == NULL)
>                               fatalx("King Bula has no prefixset");
> -                     if (last_prefixset->roa) {
> +                     if (last_set) {
>                               set_prep(last_set);
>                               rv = trie_roa_add(&last_prefixset->th,
>                                   &psi.p.addr, psi.p.len, last_set);
> @@ -1126,6 +1139,10 @@ rde_update_dispatch(struct imsg *imsg)
>                       }
>               }
>  
> +             if (state.aspath.flags & F_ATTR_ASPATH)
> +                     state.aspath.source_as =
> +                         aspath_origin(state.aspath.aspath);
> +
>               rde_reflector(peer, &state.aspath);
>       }
>  
> @@ -1384,12 +1401,17 @@ rde_update_update(struct rde_peer *peer,
>       struct filterstate       state;
>       struct prefix           *p;
>       enum filter_actions      action;
> +     u_int8_t                 vstate;
>       u_int16_t                i;
>       const char              *wmsg = "filtered, withdraw";
>  
>       peer->prefix_rcvd_update++;
> +     vstate = rde_roa_validity(&conf->rde_roa, prefix, prefixlen,
> +         in->aspath.source_as);
> +
>       /* add original path to the Adj-RIB-In */
> -     if (path_update(&ribs[RIB_ADJ_IN].rib, peer, in, prefix, prefixlen))
> +     if (path_update(&ribs[RIB_ADJ_IN].rib, peer, in, prefix, prefixlen,
> +         vstate))
>               peer->prefix_cnt++;
>  
>       /* max prefix checker */
> @@ -1420,7 +1442,7 @@ rde_update_update(struct rde_peer *peer,
>                           &state.nexthop->exit_nexthop, prefix,
>                           prefixlen);
>                       path_update(&ribs[i].rib, peer, &state, prefix,
> -                         prefixlen);
> +                         prefixlen, vstate);
>               } else if (prefix_remove(&ribs[i].rib, peer, prefix,
>                   prefixlen)) {
>                       rde_update_log(wmsg, i, peer,
> @@ -2827,16 +2849,21 @@ rde_reload_done(void)
>                       nconf->flags &= ~BGPD_FLAG_NO_EVALUATE;
>       }
>  
> -     prefixsets_old = conf->rde_prefixsets;
> -     roasets_old = conf->rde_roasets;
> +     SIMPLEQ_INIT(&prefixsets_old);
> +     SIMPLEQ_INIT(&originsets_old);
> +     SIMPLEQ_CONCAT(&prefixsets_old, &conf->rde_prefixsets);
> +     SIMPLEQ_CONCAT(&originsets_old, &conf->rde_originsets);
> +     roa_old = conf->rde_roa;
>       as_sets_old = conf->as_sets;
>  
>       memcpy(conf, nconf, sizeof(struct bgpd_config));
>       conf->listen_addrs = NULL;
>       conf->csock = NULL;
>       conf->rcsock = NULL;
> -     conf->prefixsets = NULL;
> -     conf->roasets = NULL;
> +     SIMPLEQ_INIT(&conf->rde_prefixsets);
> +     SIMPLEQ_INIT(&conf->rde_originsets);
> +     SIMPLEQ_CONCAT(&conf->rde_prefixsets, &nconf->rde_prefixsets);
> +     SIMPLEQ_CONCAT(&conf->rde_originsets, &nconf->rde_originsets);
>       free(nconf);
>       nconf = NULL;
>  
> @@ -2860,17 +2887,19 @@ rde_reload_done(void)
>       rdomains_l = newdomains;
>       /* XXX WHERE IS THE SYNC ??? */
>  
> -     rde_mark_prefixsets_dirty(prefixsets_old, prefixsets_tmp);
> -     rde_mark_prefixsets_dirty(roasets_old, roasets_tmp);
> +     /* check if roa changed */
> +     if (trie_equal(&conf->rde_roa.th, &roa_old.th) == 0) {
> +             log_debug("roa change: reloading Adj-RIB-In");
> +             conf->rde_roa.dirty = 1;
> +             reload++;       /* run softreconf in */
> +     }
> +     trie_free(&roa_old.th); /* old roa no longer needed */
> +
> +     rde_mark_prefixsets_dirty(&prefixsets_old, &conf->rde_prefixsets);
> +     rde_mark_prefixsets_dirty(&originsets_old, &conf->rde_originsets);
>       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 */
> +     /* swap the as_sets */
>       conf->as_sets = as_sets_tmp;
>       as_sets_tmp = NULL;
>  
> @@ -3059,10 +3088,8 @@ rde_softreconfig_done(void)
>               ribs[rid].state = RECONF_NONE;
>       }
>  
> -     rde_free_prefixsets(prefixsets_old);
> -     prefixsets_old = NULL;
> -     rde_free_prefixsets(roasets_old);
> -     roasets_old = NULL;
> +     rde_free_prefixsets(&prefixsets_old);
> +     rde_free_prefixsets(&originsets_old);
>       as_sets_free(as_sets_old);
>       as_sets_old = NULL;
>  
> @@ -3081,25 +3108,39 @@ rde_softreconfig_in(struct rib_entry *re
>       struct rde_peer         *peer;
>       struct rde_aspath       *asp;
>       enum filter_actions      action;
> -     struct bgpd_addr         addr;
> +     struct bgpd_addr         prefix;
> +     int                      force_eval;
> +     u_int8_t                 vstate;
>       u_int16_t                i;
>  
>       pt = re->prefix;
> -     pt_getaddr(pt, &addr);
> +     pt_getaddr(pt, &prefix);
>       LIST_FOREACH(p, &re->prefix_h, rib_l) {
>               asp = prefix_aspath(p);
>               peer = prefix_peer(p);
> +             force_eval = 0;
> +
> +             if (conf->rde_roa.dirty) {
> +                     /* ROA validation state update */
> +                     vstate = rde_roa_validity(&conf->rde_roa,
> +                         &prefix, pt->prefixlen, asp->source_as);
> +                     if (vstate != p->validation_state) {
> +                             force_eval = 1;
> +                             p->validation_state = vstate;
> +                     }
> +             }
>  
>               /* skip announced networks, they are never filtered */
>               if (asp->flags & F_PREFIX_ANNOUNCED)
>                       continue;
>  
>               for (i = RIB_LOC_START; i < rib_size; i++) {
> +                     if (!rib_valid(i))
> +                             continue;
> +
>                       rib = &ribs[i];
> -                     if (rib->state != RECONF_RELOAD)
> +                     if (rib->state != RECONF_RELOAD && !force_eval)
>                               continue;
> -                     if (!rib_valid(i))
> -                             break;
>  
>                       rde_filterstate_prep(&state, asp, prefix_nexthop(p),
>                           prefix_nhflags(p));
> @@ -3107,11 +3148,11 @@ rde_softreconfig_in(struct rib_entry *re
>  
>                       if (action == ACTION_ALLOW) {
>                               /* update Local-RIB */
> -                             path_update(&rib->rib, peer, &state, &addr,
> -                                 pt->prefixlen);
> +                             path_update(&rib->rib, peer, &state, &prefix,
> +                                 pt->prefixlen, vstate);
>                       } else if (action == ACTION_DENY) {
>                               /* remove from Local-RIB */
> -                             prefix_remove(&rib->rib, peer, &addr,
> +                             prefix_remove(&rib->rib, peer, &prefix,
>                                   pt->prefixlen);
>                       }
>  
> @@ -3620,6 +3661,7 @@ network_add(struct network_config *nc, i
>       struct rde_aspath       *asp;
>       struct filter_set_head  *vpnset = NULL;
>       in_addr_t                prefix4;
> +     u_int8_t                 vstate;
>       u_int16_t                i;
>  
>       if (nc->rtableid != conf->default_tableid) {
> @@ -3664,6 +3706,7 @@ network_add(struct network_config *nc, i
>               asp = path_get();
>               asp->aspath = aspath_get(NULL, 0);
>               asp->origin = ORIGIN_IGP;
> +             asp->source_as = aspath_origin(asp->aspath);
>               asp->flags = F_ATTR_ORIGIN | F_ATTR_ASPATH |
>                   F_ATTR_LOCALPREF | F_PREFIX_ANNOUNCED;
>               /* the nexthop is unset unless a default set overrides it */
> @@ -3676,8 +3719,10 @@ network_add(struct network_config *nc, i
>               rde_apply_set(vpnset, &state, nc->prefix.aid, peerself,
>                   peerself);
>  
> +     vstate = rde_roa_validity(&conf->rde_roa, &nc->prefix,
> +         nc->prefixlen, asp->source_as);
>       if (path_update(&ribs[RIB_ADJ_IN].rib, peerself, &state, &nc->prefix,
> -                 nc->prefixlen))
> +                 nc->prefixlen, vstate))
>               peerself->prefix_cnt++;
>       for (i = RIB_LOC_START; i < rib_size; i++) {
>               if (!rib_valid(i))
> @@ -3686,7 +3731,7 @@ network_add(struct network_config *nc, i
>                   state.nexthop ? &state.nexthop->exit_nexthop : NULL,
>                   &nc->prefix, nc->prefixlen);
>               path_update(&ribs[i].rib, peerself, &state, &nc->prefix,
> -                 nc->prefixlen);
> +                 nc->prefixlen, vstate);
>       }
>       rde_filterstate_clean(&state);
>       path_put(asp);
> @@ -3895,4 +3940,14 @@ rde_mark_prefixsets_dirty(struct rde_pre
>                               new->dirty = 1;
>               }
>       }
> +}
> +
> +u_int8_t
> +rde_roa_validity(struct rde_prefixset *ps, struct bgpd_addr *prefix,
> +    u_int8_t plen, u_int32_t as)
> +{
> +     int r;
> +
> +     r = trie_roa_check(&ps->th, prefix, plen, as);
> +     return (r & ROA_MASK);
>  }
> Index: rde.h
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
> retrieving revision 1.193
> diff -u -p -r1.193 rde.h
> --- rde.h     20 Sep 2018 11:45:59 -0000      1.193
> +++ rde.h     26 Sep 2018 14:30:41 -0000
> @@ -36,11 +36,10 @@ enum peer_state {
>       PEER_ERR        /* error occurred going to PEER_DOWN state */
>  };
>  
> -enum roa_state {
> -     ROA_UNKNOWN,
> -     ROA_INVALID,
> -     ROA_VALID
> -};
> +#define      ROA_NOTFOUND    0x0     /* default */
> +#define      ROA_INVALID     0x1
> +#define      ROA_VALID       0x2
> +#define      ROA_MASK        0x3
>  
>  /*
>   * How do we identify peers between the session handler and the rde?
> @@ -191,6 +190,7 @@ struct rde_aspath {
>       struct aspath                   *aspath;
>       u_int64_t                        hash;
>       u_int32_t                        flags;         /* internally used */
> +     u_int32_t                        source_as;     /* cached source_as */
>       u_int32_t                        med;           /* multi exit disc */
>       u_int32_t                        lpref;         /* local pref */
>       u_int32_t                        weight;        /* low prio lpref */
> @@ -311,6 +311,7 @@ struct prefix {
>       struct rde_peer                 *peer;
>       struct nexthop                  *nexthop;       /* may be NULL */
>       time_t                           lastchange;
> +     u_int8_t                         validation_state;
>       u_int8_t                         nhflags;
>  };
>  
> @@ -325,24 +326,6 @@ struct filterstate {
>       u_int8_t                 nhflags;
>  };
>  
> -struct tentry_v4;
> -struct tentry_v6;
> -struct trie_head {
> -     struct tentry_v4        *root_v4;
> -     struct tentry_v6        *root_v6;
> -     int                      match_default_v4;
> -     int                      match_default_v6;
> -};
> -
> -struct rde_prefixset {
> -     char                            name[SET_NAME_LEN];
> -     struct trie_head                th;
> -     SIMPLEQ_ENTRY(rde_prefixset)    entry;
> -     int                             dirty;
> -     int                             roa;
> -};
> -SIMPLEQ_HEAD(rde_prefixset_head, rde_prefixset);
> -
>  extern struct rde_memstats rdemem;
>  
>  /* prototypes */
> @@ -396,6 +379,7 @@ u_char            *aspath_dump(struct aspath *);
>  u_int16_t     aspath_length(struct aspath *);
>  u_int16_t     aspath_count(const void *, u_int16_t);
>  u_int32_t     aspath_neighbor(struct aspath *);
> +u_int32_t     aspath_origin(struct aspath *);
>  int           aspath_loopfree(struct aspath *, u_int32_t);
>  int           aspath_compare(struct aspath *, struct aspath *);
>  u_char               *aspath_prepend(struct aspath *, u_int32_t, int, 
> u_int16_t *);
> @@ -501,7 +485,7 @@ void               path_init(u_int32_t);
>  void          path_shutdown(void);
>  void          path_hash_stats(struct rde_hashstats *);
>  int           path_update(struct rib *, struct rde_peer *,
> -                  struct filterstate *, struct bgpd_addr *, int);
> +                  struct filterstate *, struct bgpd_addr *, int, u_int8_t);
>  int           path_compare(struct rde_aspath *, struct rde_aspath *);
>  void          path_remove(struct rde_aspath *);
>  u_int32_t     path_remove_stale(struct rde_aspath *, u_int8_t, time_t);
> @@ -549,6 +533,12 @@ static inline u_int8_t
>  prefix_nhflags(struct prefix *p)
>  {
>       return (p->nhflags);
> +}
> +
> +static inline u_int8_t
> +prefix_vstate(struct prefix *p)
> +{
> +     return (p->validation_state & ROA_MASK);
>  }
>  
>  void          nexthop_init(u_int32_t);
> Index: rde_attr.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_attr.c,v
> retrieving revision 1.110
> diff -u -p -r1.110 rde_attr.c
> --- rde_attr.c        20 Sep 2018 11:06:04 -0000      1.110
> +++ rde_attr.c        21 Sep 2018 12:26:46 -0000
> @@ -586,7 +586,7 @@ aspath_deflate(u_char *data, u_int16_t *
>               nlen += 2 + sizeof(u_int16_t) * seg_len;
>  
>               if (seg_size > olen)
> -                     fatalx("aspath_deflate: would overflow");
> +                     fatalx("%s: would overflow", __func__);
>       }
>  
>       if ((ndata = malloc(nlen)) == NULL)
> @@ -687,7 +687,7 @@ aspath_count(const void *data, u_int16_t
>                       cnt += seg_len;
>  
>               if (seg_size > len)
> -                     fatalx("aspath_count: would overflow");
> +                     fatalx("%s: would overflow", __func__);
>       }
>       return (cnt);
>  }
> @@ -719,7 +719,7 @@ aspath_countlength(struct aspath *aspath
>               clen += seg_size;
>  
>               if (seg_size > len)
> -                     fatalx("aspath_countlength: would overflow");
> +                     fatalx("%s: would overflow", __func__);
>       }
>       if (headcnt > 0 && seg_type == AS_SEQUENCE && headcnt + seg_len < 256)
>               /* no need for additional header from the new aspath. */
> @@ -766,7 +766,7 @@ aspath_countcopy(struct aspath *aspath, 
>               buf[1] = seg_len;
>               buf += seg_size;
>               if (size < seg_size)
> -                     fatalx("aspath_countlength: would overflow");
> +                     fatalx("%s: would overflow", __func__);
>               size -= seg_size;
>       }
>  }
> @@ -780,6 +780,41 @@ aspath_neighbor(struct aspath *aspath)
>       return (aspath_extract(aspath->data, 0));
>  }
>  
> +/*
> + * The origin AS number derived from a Route as follows:
> + * o  the rightmost AS in the final segment of the AS_PATH attribute
> + *    in the Route if that segment is of type AS_SEQUENCE, or
> + * o  the BGP speaker's own AS number if that segment is of type
> + *    AS_CONFED_SEQUENCE or AS_CONFED_SET or if the AS_PATH is empty,
> + * o  the distinguished value "NONE" if the final segment of the
> + *   AS_PATH attribute is of any other type.
> + */
> +u_int32_t
> +aspath_origin(struct aspath *aspath)
> +{
> +     u_int8_t        *seg;
> +     u_int32_t        as = AS_NONE;
> +     u_int16_t        len, seg_size;
> +     u_int8_t         seg_len;
> +
> +     /* AS_PATH is empty */
> +     if (aspath->len == 0)
> +             return (rde_local_as());
> +
> +     seg = aspath->data;
> +     for (len = aspath->len; len > 0; len -= seg_size, seg += seg_size) {
> +             seg_len = seg[1];
> +             seg_size = 2 + sizeof(u_int32_t) * seg_len;
> +
> +             if (len == seg_size && seg[0] == AS_SEQUENCE) {
> +                     as = aspath_extract(seg, seg_len - 1);
> +             }
> +             if (seg_size > len)
> +                     fatalx("%s: would overflow", __func__);
> +     }
> +     return (as);
> +}
> +
>  int
>  aspath_loopfree(struct aspath *aspath, u_int32_t myAS)
>  {
> @@ -798,7 +833,7 @@ aspath_loopfree(struct aspath *aspath, u
>               }
>  
>               if (seg_size > len)
> -                     fatalx("aspath_loopfree: would overflow");
> +                     fatalx("%s: would overflow", __func__);
>       }
>       return (1);
>  }
> Index: rde_filter.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_filter.c,v
> retrieving revision 1.111
> diff -u -p -r1.111 rde_filter.c
> --- rde_filter.c      26 Sep 2018 15:48:01 -0000      1.111
> +++ rde_filter.c      27 Sep 2018 08:44:14 -0000
> @@ -360,6 +360,11 @@ rde_filter_match(struct filter_rule *f, 
>       if (f->peer.ibgp && peer->conf.ebgp)
>               return (0);
>  
> +     if (f->match.ovs.is_set) {
> +             if (prefix_vstate(p) != f->match.ovs.validity)
> +                     return (0);
> +     }
> +
>       if (asp != NULL && f->match.as.type != AS_UNDEF) {
>               if (aspath_match(asp->aspath->data, asp->aspath->len,
>                   &f->match.as, peer->conf.remote_as) == 0)
> @@ -408,8 +413,7 @@ rde_filter_match(struct filter_rule *f, 
>               if (community_ext_match(asp, &f->match.ext_community,
>                   peer->conf.remote_as) == 0)
>                       return (0);
> -     if (asp != NULL && f->match.large_community.as !=
> -         COMMUNITY_UNSET) {
> +     if (asp != NULL && f->match.large_community.as != COMMUNITY_UNSET) {
>               switch (f->match.large_community.as) {
>               case COMMUNITY_ERROR:
>                       fatalx("rde_filter_match bad community string");
> @@ -485,6 +489,18 @@ rde_filter_match(struct filter_rule *f, 
>               }
>       }
>  
> +     /* origin-set lookups match only on ROA_VALID */
> +     if (asp != NULL && f->match.originset.ps != NULL) {
> +             struct bgpd_addr addr, *prefix = &addr;
> +             u_int8_t plen;
> +
> +             pt_getaddr(p->re->prefix, prefix);
> +             plen = p->re->prefix->prefixlen;
> +             if (trie_roa_check(&f->match.originset.ps->th, prefix, plen,
> +                 asp->source_as) != ROA_VALID)
> +                     return (0);
> +     }
> +
>       /*
>        * prefixset and prefix filter rules are mutual exclusive
>        */
> @@ -578,7 +594,7 @@ rde_filter_equal(struct filter_head *a, 
>      struct rde_peer *peer)
>  {
>       struct filter_rule      *fa, *fb;
> -     struct rde_prefixset    *psa, *psb;
> +     struct rde_prefixset    *psa, *psb, *osa, *osb;
>       struct as_set           *asa, *asb;
>       int                      r;
>  
> @@ -609,26 +625,35 @@ rde_filter_equal(struct filter_head *a, 
>               /* compare filter_rule.match without the prefixset pointer */
>               psa = fa->match.prefixset.ps;
>               psb = fb->match.prefixset.ps;
> +             osa = fa->match.originset.ps;
> +             osb = fb->match.originset.ps;
>               asa = fa->match.as.aset;
>               asb = fb->match.as.aset;
>               fa->match.prefixset.ps = fb->match.prefixset.ps = NULL;
> +             fa->match.originset.ps = fb->match.originset.ps = NULL;
>               fa->match.as.aset = fb->match.as.aset = NULL;
>               r = memcmp(&fa->match, &fb->match, sizeof(fa->match));
>               /* fixup the struct again */
>               fa->match.prefixset.ps = psa;
>               fb->match.prefixset.ps = psb;
> +             fa->match.originset.ps = osa;
> +             fb->match.originset.ps = osb;
>               fa->match.as.aset = asa;
>               fb->match.as.aset = asb;
>               if (r != 0)
>                       return (0);
> -             if (fa->match.prefixset.flags != 0 &&
> -                 fa->match.prefixset.ps != NULL &&
> +             if (fa->match.prefixset.ps != NULL &&
>                   fa->match.prefixset.ps->dirty) {
>                       log_debug("%s: prefixset %s has changed",
>                           __func__, fa->match.prefixset.name);
>                       return (0);
>               }
> -
> +             if (fa->match.originset.ps != NULL &&
> +                 fa->match.originset.ps->dirty) {
> +                     log_debug("%s: originset %s has changed",
> +                         __func__, fa->match.originset.name);
> +                     return (0);
> +             }
>               if ((fa->match.as.flags & AS_FLAG_AS_SET) &&
>                   fa->match.as.aset->dirty) {
>                       log_debug("%s: as-set %s has changed",
> Index: rde_rib.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
> retrieving revision 1.178
> diff -u -p -r1.178 rde_rib.c
> --- rde_rib.c 20 Sep 2018 11:06:04 -0000      1.178
> +++ rde_rib.c 26 Sep 2018 14:20:41 -0000
> @@ -48,11 +48,11 @@ struct rib_entry *rib_restart(struct rib
>  RB_PROTOTYPE(rib_tree, rib_entry, rib_e, rib_compare);
>  RB_GENERATE(rib_tree, rib_entry, rib_e, rib_compare);
>  
> -int           prefix_add(struct bgpd_addr *, int, struct rib *,
> +static int    prefix_add(struct bgpd_addr *, int, struct rib *,
>                   struct rde_peer *, struct rde_aspath *,
> -                 struct filterstate *);
> -int           prefix_move(struct prefix *, struct rde_peer *,
> -                 struct rde_aspath *, struct filterstate *);
> +                 struct filterstate *, u_int8_t);
> +static int    prefix_move(struct prefix *, struct rde_peer *,
> +                 struct rde_aspath *, struct filterstate *, u_int8_t);
>  
>  static inline void
>  re_lock(struct rib_entry *re)
> @@ -419,7 +419,7 @@ path_hash_stats(struct rde_hashstats *hs
>  
>  int
>  path_update(struct rib *rib, struct rde_peer *peer, struct filterstate 
> *state,
> -    struct bgpd_addr *prefix, int prefixlen)
> +    struct bgpd_addr *prefix, int prefixlen, u_int8_t vstate)
>  {
>       struct rde_aspath       *asp, *nasp = &state->aspath;
>       struct prefix           *p;
> @@ -438,6 +438,7 @@ path_update(struct rib *rib, struct rde_
>                   prefix_nhflags(p) == state->nhflags) {
>                       /* no change, update last change */
>                       p->lastchange = time(NULL);
> +                     p->validation_state = vstate;
>                       return (0);
>               }
>       }
> @@ -455,10 +456,10 @@ path_update(struct rib *rib, struct rde_
>  
>       /* If the prefix was found move it else add it to the aspath. */
>       if (p != NULL)
> -             return (prefix_move(p, peer, asp, state));
> +             return (prefix_move(p, peer, asp, state, vstate));
>       else
>               return (prefix_add(prefix, prefixlen, rib, peer, asp,
> -                 state));
> +                 state, vstate));
>  }
>  
>  int
> @@ -500,6 +501,10 @@ path_compare(struct rde_aspath *a, struc
>               return (1);
>       if (a->pftableid < b->pftableid)
>               return (-1);
> +     if (a->source_as > b->source_as)
> +             return (1);
> +     if (a->source_as < b->source_as)
> +             return (-1);
>  
>       r = aspath_compare(a->aspath, b->aspath);
>       if (r > 0)
> @@ -673,6 +678,7 @@ path_copy(struct rde_aspath *dst, const 
>       dst->lpref = src->lpref;
>       dst->weight = src->weight;
>       dst->origin = src->origin;
> +     dst->source_as = src->source_as;
>       dst->rtlabelid = rtlabel_ref(src->rtlabelid);
>       dst->pftableid = pftable_ref(src->pftableid);
>  
> @@ -739,7 +745,7 @@ static struct prefix      *prefix_alloc(void)
>  static void           prefix_free(struct prefix *);
>  static void           prefix_link(struct prefix *, struct rib_entry *,
>                            struct rde_peer *, struct rde_aspath *,
> -                          struct filterstate *);
> +                          struct filterstate *, u_int8_t);
>  static void           prefix_unlink(struct prefix *);
>  
>  /*
> @@ -760,9 +766,10 @@ prefix_get(struct rib *rib, struct rde_p
>  /*
>   * Adds or updates a prefix.
>   */
> -int
> +static int
>  prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
> -    struct rde_peer *peer, struct rde_aspath *asp, struct filterstate *state)
> +    struct rde_peer *peer, struct rde_aspath *asp, struct filterstate *state,
> +    u_int8_t vstate)
>  {
>       struct prefix           *p;
>       struct rib_entry        *re;
> @@ -774,16 +781,17 @@ prefix_add(struct bgpd_addr *prefix, int
>       p = prefix_bypeer(re, asp->peer);
>       if (p == NULL) {
>               p = prefix_alloc();
> -             prefix_link(p, re, peer, asp, state);
> +             prefix_link(p, re, peer, asp, state, vstate);
>               return (1);
>       } else {
>               if (prefix_aspath(p) != asp ||
>                   prefix_nexthop(p) != state->nexthop ||
>                   prefix_nhflags(p) != state->nhflags) {
>                       /* prefix metadata changed therefor move */
> -                     return (prefix_move(p, peer, asp, state));
> +                     return (prefix_move(p, peer, asp, state, vstate));
>               }
>               p->lastchange = time(NULL);
> +             p->validation_state = vstate;
>               return (0);
>       }
>  }
> @@ -791,9 +799,9 @@ prefix_add(struct bgpd_addr *prefix, int
>  /*
>   * Move the prefix to the specified as path, removes the old asp if needed.
>   */
> -int
> +static int
>  prefix_move(struct prefix *p, struct rde_peer *peer,
> -    struct rde_aspath *asp, struct filterstate *state)
> +    struct rde_aspath *asp, struct filterstate *state, u_int8_t vstate)
>  {
>       struct prefix           *np;
>       struct rde_aspath       *oasp;
> @@ -809,6 +817,7 @@ prefix_move(struct prefix *p, struct rde
>       np->re = p->re;
>       np->lastchange = time(NULL);
>       np->nhflags = state->nhflags;
> +     np->validation_state = vstate;
>  
>       /* add to new as path */
>       TAILQ_INSERT_HEAD(&asp->prefixes, np, path_l);
> @@ -1057,7 +1066,7 @@ prefix_network_clean(struct rde_peer *pe
>   */
>  static void
>  prefix_link(struct prefix *pref, struct rib_entry *re, struct rde_peer *peer,
> -    struct rde_aspath *asp, struct filterstate *state)
> +    struct rde_aspath *asp, struct filterstate *state, u_int8_t vstate)
>  {
>       TAILQ_INSERT_HEAD(&asp->prefixes, pref, path_l);
>  
> @@ -1068,6 +1077,7 @@ prefix_link(struct prefix *pref, struct 
>       pref->re = re;
>       pref->lastchange = time(NULL);
>       pref->nhflags = state->nhflags;
> +     pref->validation_state = vstate;
>  
>       /* make route decision */
>       prefix_evaluate(pref, re);
> Index: rde_trie.c
> ===================================================================
> RCS file: /cvs/src/usr.sbin/bgpd/rde_trie.c,v
> retrieving revision 1.8
> diff -u -p -r1.8 rde_trie.c
> --- rde_trie.c        26 Sep 2018 14:47:20 -0000      1.8
> +++ rde_trie.c        26 Sep 2018 14:49:31 -0000
> @@ -543,7 +543,7 @@ trie_roa_check_v4(struct trie_head *th, 
>  {
>       struct tentry_v4 *n;
>       struct roa_set *rs;
> -     int validity = ROA_UNKNOWN;
> +     int validity = ROA_NOTFOUND;
>  
>       /* ignore possible default route since it does not make sense */
>  
> @@ -565,8 +565,8 @@ trie_roa_check_v4(struct trie_head *th, 
>                        */
>                       validity = ROA_INVALID;
>  
> -                     /* Treat AS 0 as NONE which can never be matched */
> -                     if (as != 0) {
> +                     /* AS_NONE can never match, so don't try */
> +                     if (as != AS_NONE) {
>                               if ((rs = set_match(n->set, as)) != NULL) {
>                                   if (plen == n->plen || plen <= rs->maxlen)
>                                       return ROA_VALID;
> @@ -591,7 +591,7 @@ trie_roa_check_v6(struct trie_head *th, 
>  {
>       struct tentry_v6 *n;
>       struct roa_set *rs;
> -     int validity = ROA_UNKNOWN;
> +     int validity = ROA_NOTFOUND;
>  
>       /* ignore possible default route since it does not make sense */
>  
> @@ -613,8 +613,8 @@ trie_roa_check_v6(struct trie_head *th, 
>                        */
>                       validity = ROA_INVALID;
>  
> -                     /* Treat AS 0 as NONE which can never be matched */
> -                     if (as != 0) {
> +                     /* AS_NONE can never match, so don't try */
> +                     if (as != AS_NONE) {
>                               if ((rs = set_match(n->set, as)) != NULL)
>                                   if (plen == n->plen || plen <= rs->maxlen)
>                                       return ROA_VALID;
> @@ -635,9 +635,9 @@ trie_roa_check_v6(struct trie_head *th, 
>  /*
>   * Do a ROA (Route Origin Validation) check.  Look for elements in the trie
>   * which cover prefix "prefix/plen" and match the source-as as.
> - * AS 0 is treated here like AS NONE and should be used when the source-as
> - * is unknown (e.g. AS_SET). In other words the check will then only return
> - * ROA_UNKNOWN or ROA_INVALID depending if the prefix is covered by the ROA.
> + * AS_NONE can be used when the source-as is unknown (e.g. AS_SET).
> + * The check will then only return ROA_NOTFOUND or ROA_INVALID depending if
> + * the prefix is covered by the ROA.
>   */
>  int
>  trie_roa_check(struct trie_head *th, struct bgpd_addr *prefix, u_int8_t plen,
> @@ -650,8 +650,8 @@ trie_roa_check(struct trie_head *th, str
>       case AID_INET6:
>               return trie_roa_check_v6(th, &prefix->v6, plen, as);
>       default:
> -             /* anything else is unknown */
> -             return ROA_UNKNOWN;
> +             /* anything else is not-found */
> +             return ROA_NOTFOUND;
>       }
>  }
>  
> 

Reply via email to