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