This is the next step for ROA validation.
Implement code to parse, print and reload roa-set tables.
This is sharing a lot of code with prefixset which makes all a bit easier.
A roa-set is defined like this:
roa-set "test2" {
1.2.3.0/24 source-as 1,
1.2.8.0/22 source-as 3
}
This does not include any code to acutally use the data yet, I'm working
on that now and that will be then the next and hopefully last diff to
support ROA validations in bgpd.
--
:wq Claudio
Index: bgpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
retrieving revision 1.200
diff -u -p -r1.200 bgpd.c
--- bgpd.c 20 Sep 2018 11:45:59 -0000 1.200
+++ bgpd.c 20 Sep 2018 11:49:56 -0000
@@ -516,6 +516,34 @@ reconfigure(char *conffile, struct bgpd_
if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSETITEM, 0,
0, -1, psi, sizeof(*psi)) == -1)
return (-1);
+ set_free(psi->set);
+ free(psi);
+ }
+ free(ps);
+ }
+
+ /* roasets for filters in the RDE */
+ while ((ps = SIMPLEQ_FIRST(conf->roasets)) != NULL) {
+ SIMPLEQ_REMOVE_HEAD(conf->roasets, entry);
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_ROA_SET, 0, 0, -1,
+ ps->name, sizeof(ps->name)) == -1)
+ return (-1);
+ RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) {
+ u_int32_t *as;
+ size_t i, l, n;
+ RB_REMOVE(prefixset_tree, &ps->psitems, psi);
+ as = set_get(psi->set, &n);
+ for (i = 0; i < n; i += l) {
+ l = (n - i > 1024 ? 1024 : n - i);
+ if (imsg_compose(ibuf_rde,
+ IMSG_RECONF_ROA_AS_SET_ITEMS,
+ 0, 0, -1, as + i, l) == -1)
+ return -1;
+ }
+ if (imsg_compose(ibuf_rde, IMSG_RECONF_PREFIXSETITEM, 0,
+ 0, -1, psi, sizeof(*psi)) == -1)
+ return (-1);
+ set_free(psi->set);
free(psi);
}
free(ps);
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.343
diff -u -p -r1.343 bgpd.h
--- bgpd.h 20 Sep 2018 11:45:59 -0000 1.343
+++ bgpd.h 20 Sep 2018 11:49:56 -0000
@@ -229,7 +229,9 @@ struct bgpd_config {
struct listen_addrs *listen_addrs;
struct mrt_head *mrt;
struct prefixset_head *prefixsets;
+ struct prefixset_head *roasets;
struct rde_prefixset_head *rde_prefixsets;
+ struct rde_prefixset_head *rde_roasets;
struct as_set_head *as_sets;
char *csock;
char *rcsock;
@@ -431,6 +433,8 @@ enum imsg_type {
IMSG_RECONF_AS_SET,
IMSG_RECONF_AS_SET_ITEMS,
IMSG_RECONF_AS_SET_DONE,
+ IMSG_RECONF_ROA_SET,
+ IMSG_RECONF_ROA_AS_SET_ITEMS,
IMSG_RECONF_DONE,
IMSG_UPDATE,
IMSG_UPDATE_ERR,
@@ -961,6 +965,7 @@ struct roa_set {
struct prefixset_item {
struct filter_prefix p;
RB_ENTRY(prefixset_item) entry;
+ struct set_table *set;
};
RB_HEAD(prefixset_tree, prefixset_item);
Index: config.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/config.c,v
retrieving revision 1.74
diff -u -p -r1.74 config.c
--- config.c 20 Sep 2018 07:46:39 -0000 1.74
+++ config.c 20 Sep 2018 11:49:56 -0000
@@ -67,6 +67,8 @@ new_config(void)
if ((conf->prefixsets = calloc(1, sizeof(struct prefixset_head)))
== NULL)
fatal(NULL);
+ if ((conf->roasets = calloc(1, sizeof(struct prefixset_head))) == NULL)
+ fatal(NULL);
if ((conf->as_sets = calloc(1, sizeof(struct as_set_head))) == NULL)
fatal(NULL);
if ((conf->filters = calloc(1, sizeof(struct filter_head))) == NULL)
@@ -81,6 +83,7 @@ new_config(void)
TAILQ_INIT(&conf->networks);
SIMPLEQ_INIT(&conf->rdomains);
SIMPLEQ_INIT(conf->prefixsets);
+ SIMPLEQ_INIT(conf->roasets);
SIMPLEQ_INIT(conf->as_sets);
TAILQ_INIT(conf->filters);
@@ -129,6 +132,7 @@ free_prefixsets(struct prefixset_head *p
ps = SIMPLEQ_FIRST(psh);
RB_FOREACH_SAFE(psi, prefixset_tree, &ps->psitems, npsi) {
RB_REMOVE(prefixset_tree, &ps->psitems, psi);
+ set_free(psi->set);
free(psi);
}
SIMPLEQ_REMOVE_HEAD(psh, entry);
@@ -147,6 +151,7 @@ free_config(struct bgpd_config *conf)
free_networks(&conf->networks);
filterlist_free(conf->filters);
free_prefixsets(conf->prefixsets);
+ free_prefixsets(conf->roasets);
as_sets_free(conf->as_sets);
while ((la = TAILQ_FIRST(conf->listen_addrs)) != NULL) {
@@ -224,6 +229,11 @@ merge_config(struct bgpd_config *xconf,
free_prefixsets(xconf->prefixsets);
xconf->prefixsets = conf->prefixsets;
conf->prefixsets = NULL;
+
+ /* switch the roasets, first remove the old ones */
+ free_prefixsets(xconf->roasets);
+ xconf->roasets = conf->roasets;
+ conf->roasets = NULL;
/* switch the as_sets, first remove the old ones */
as_sets_free(xconf->as_sets);
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.355
diff -u -p -r1.355 parse.y
--- parse.y 20 Sep 2018 11:45:59 -0000 1.355
+++ parse.y 20 Sep 2018 11:49:57 -0000
@@ -93,6 +93,7 @@ static struct peer *curpeer;
static struct peer *curgroup;
static struct rdomain *currdom;
static struct prefixset *curpset;
+static struct prefixset *curroaset;
static struct filter_head *filter_l;
static struct filter_head *peerfilter_l;
static struct filter_head *groupfilter_l;
@@ -162,7 +163,8 @@ int parseextcommunity(struct filter_ex
static int new_as_set(char *);
static void add_as_set(u_int32_t);
static void done_as_set(void);
-static int new_prefix_set(char *);
+static struct prefixset *new_prefix_set(char *, int);
+static void add_roa_set(struct prefixset_item *, u_int32_t, u_int8_t);
typedef struct {
union {
@@ -211,7 +213,7 @@ typedef struct {
%token FROM TO ANY
%token CONNECTED STATIC
%token COMMUNITY EXTCOMMUNITY LARGECOMMUNITY DELETE
-%token PREFIX PREFIXLEN PREFIXSET
+%token PREFIX PREFIXLEN PREFIXSET ROASET
%token ASSET SOURCEAS TRANSITAS PEERAS MAXASLEN MAXASSEQ
%token SET LOCALPREF MED METRIC NEXTHOP REJECT BLACKHOLE NOMODIFY SELF
%token PREPEND_SELF PREPEND_PEER PFTABLE WEIGHT RTLABEL ORIGIN PRIORITY
@@ -250,6 +252,7 @@ grammar : /* empty */
| grammar include '\n'
| grammar as_set '\n'
| grammar prefixset '\n'
+ | grammar roa_set '\n'
| grammar conf_main '\n'
| grammar rdomain '\n'
| grammar neighbor '\n'
@@ -423,7 +426,7 @@ as_set_l : as4number_any { add_as_set(
| as_set_l comma as4number_any { add_as_set($3); }
prefixset : PREFIXSET STRING '{' optnl {
- if (new_prefix_set($2) != 0) {
+ if ((curpset = new_prefix_set($2, 0)) == NULL) {
free($2);
YYERROR;
}
@@ -433,7 +436,7 @@ prefixset : PREFIXSET STRING '{' optnl
curpset = NULL;
}
| PREFIXSET STRING '{' optnl '}' {
- if (new_prefix_set($2) != 0) {
+ if ((curpset = new_prefix_set($2, 0)) == NULL) {
free($2);
YYERROR;
}
@@ -487,6 +490,47 @@ prefixset_item : prefix prefixlenop
{
}
;
+roa_set : ROASET STRING '{' optnl {
+ if ((curroaset = new_prefix_set($2, 1)) == NULL) {
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ } roa_set_l optnl '}' {
+ SIMPLEQ_INSERT_TAIL(conf->roasets, curroaset, entry);
+ curroaset = NULL;
+ }
+ | ROASET STRING '{' optnl '}' {
+ if ((curroaset = new_prefix_set($2, 1)) == NULL) {
+ free($2);
+ YYERROR;
+ }
+ free($2);
+ SIMPLEQ_INSERT_TAIL(conf->roasets, curroaset, entry);
+ curroaset = NULL;
+ }
+ ;
+
+roa_set_l : prefixset_item SOURCEAS as4number_any {
+ if ($1->p.len_min != $1->p.len) {
+ yyerror("unsupported prefixlen operation in "
+ "roa-set");
+ free($1);
+ YYERROR;
+ }
+ add_roa_set($1, $3, $1->p.len_max);
+ }
+ | roa_set_l comma prefixset_item SOURCEAS as4number_any {
+ if ($3->p.len_min != $3->p.len) {
+ yyerror("unsupported prefixlen operation in "
+ "roa-set");
+ free($3);
+ YYERROR;
+ }
+ add_roa_set($3, $5, $3->p.len_max);
+ }
+ ;
+
conf_main : AS as4number {
conf->as = $2;
if ($2 > USHRT_MAX)
@@ -2768,6 +2812,7 @@ lookup(char *s)
{ "restart", RESTART},
{ "restricted", RESTRICTED},
{ "rib", RIB},
+ { "roa-set", ROASET },
{ "route-collector", ROUTECOLL},
{ "route-reflector", REFLECTOR},
{ "router-id", ROUTERID},
@@ -4230,21 +4275,52 @@ done_as_set(void)
curset = NULL;
}
-static int
-new_prefix_set(char *name)
+static struct prefixset *
+new_prefix_set(char *name, int is_roa)
{
- if (find_prefixset(name, conf->prefixsets) != NULL) {
- yyerror("prefix-set \"%s\" already exists", name);
- return -1;
+ const char *type = "prefix-set";
+ struct prefixset_head *sets = conf->prefixsets;
+ struct prefixset *pset;
+
+ if (is_roa) {
+ type = "roa-set";
+ sets = conf->roasets;
}
- if ((curpset = calloc(1, sizeof(*curpset))) == NULL)
+
+ if (find_prefixset(name, sets) != NULL) {
+ yyerror("%s \"%s\" already exists", type, name);
+ return NULL;
+ }
+ if ((pset = calloc(1, sizeof(*pset))) == NULL)
fatal("prefixset");
- if (strlcpy(curpset->name, name, sizeof(curpset->name)) >=
- sizeof(curpset->name)) {
+ if (strlcpy(pset->name, name, sizeof(pset->name)) >=
+ sizeof(pset->name)) {
yyerror("prefix-set \"%s\" too long: max %zu",
- name, sizeof(curpset->name) - 1);
- return -1;
+ name, sizeof(pset->name) - 1);
+ free(pset);
+ return NULL;
}
- RB_INIT(&curpset->psitems);
- return 0;
+ RB_INIT(&pset->psitems);
+ return pset;
+}
+
+static void
+add_roa_set(struct prefixset_item *npsi, u_int32_t as, u_int8_t max)
+{
+ struct prefixset_item *psi;
+ struct roa_set rs;
+
+ /* no prefixlen option on this tree */
+ npsi->p.len_max = npsi->p.len_min = npsi->p.len;
+ psi = RB_INSERT(prefixset_tree, &curroaset->psitems, npsi);
+ if (psi == NULL)
+ psi = npsi;
+
+ if (psi->set == NULL)
+ if ((psi->set = set_new(1, sizeof(rs))) == NULL)
+ fatal("set_new");
+ rs.as = as;
+ rs.maxlen = max;
+ if (set_add(psi->set, &rs, 1) != 0)
+ fatal("as_set_new");
}
Index: printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.121
diff -u -p -r1.121 printconf.c
--- printconf.c 20 Sep 2018 11:45:59 -0000 1.121
+++ printconf.c 20 Sep 2018 11:49:57 -0000
@@ -42,6 +42,7 @@ const char *print_af(u_int8_t);
void print_network(struct network_config *, const char *);
void print_as_sets(struct as_set_head *);
void print_prefixsets(struct prefixset_head *);
+void print_roasets(struct prefixset_head *);
void print_peer(struct peer_config *, struct bgpd_config *,
const char *);
const char *print_auth_alg(u_int8_t);
@@ -486,6 +487,35 @@ print_prefixsets(struct prefixset_head *
}
void
+print_roasets(struct prefixset_head *psh)
+{
+ struct prefixset *ps;
+ struct prefixset_item *psi;
+ struct roa_set *rs;
+ size_t i, n;
+
+ SIMPLEQ_FOREACH(ps, psh, entry) {
+ int count = 0;
+ printf("roa-set \"%s\" {", ps->name);
+ RB_FOREACH(psi, prefixset_tree, &ps->psitems) {
+ rs = set_get(psi->set, &n);
+ for (i = 0; i < n; i++) {
+ if (count++ % 2 == 0)
+ printf("\n\t");
+ else
+ printf(", ");
+
+ print_prefix(&psi->p);
+ if (psi->p.len != rs[i].maxlen)
+ printf(" maxlen %u", rs[i].maxlen);
+ printf(" source-as %u", rs[i].as);
+ }
+ }
+ printf("\n}\n\n");
+ }
+}
+
+void
print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c)
{
char *method;
@@ -891,6 +921,7 @@ print_config(struct bgpd_config *conf, s
print_mainconf(conf);
print_prefixsets(conf->prefixsets);
print_as_sets(conf->as_sets);
+ print_roasets(conf->roasets);
TAILQ_FOREACH(n, net_l, entry)
print_network(&n->net, "");
if (!SIMPLEQ_EMPTY(rdom_l))
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.425
diff -u -p -r1.425 rde.c
--- rde.c 20 Sep 2018 11:45:59 -0000 1.425
+++ rde.c 20 Sep 2018 11:49:57 -0000
@@ -131,6 +131,7 @@ time_t reloadtime;
struct rde_peer_head peerlist;
struct rde_peer *peerself;
struct rde_prefixset_head *prefixsets_tmp, *prefixsets_old;
+struct rde_prefixset_head *roasets_tmp, *roasets_old;
struct as_set_head *as_sets_tmp, *as_sets_old;
struct filter_head *out_rules, *out_rules_tmp;
struct rdomain_head *rdomains_l, *newdomains;
@@ -689,6 +690,7 @@ rde_dispatch_imsg_parent(struct imsgbuf
{
static struct rde_prefixset *last_prefixset;
static struct as_set *last_as_set;
+ static struct set_table *last_set;
static struct rdomain *rd;
struct imsg imsg;
struct mrt xmrt;
@@ -702,7 +704,7 @@ rde_dispatch_imsg_parent(struct imsgbuf
struct prefixset_item psi;
char *name;
size_t nmemb;
- int n, fd;
+ int n, fd, rv;
u_int16_t rid;
while (ibuf) {
@@ -774,6 +776,11 @@ rde_dispatch_imsg_parent(struct imsgbuf
if (prefixsets_tmp == NULL)
fatal(NULL);
SIMPLEQ_INIT(prefixsets_tmp);
+ roasets_tmp = calloc(1,
+ sizeof(struct rde_prefixset_head));
+ if (roasets_tmp == NULL)
+ fatal(NULL);
+ SIMPLEQ_INIT(roasets_tmp);
as_sets_tmp = calloc(1,
sizeof(struct as_set_head));
if (as_sets_tmp == NULL)
@@ -877,6 +884,7 @@ rde_dispatch_imsg_parent(struct imsgbuf
TAILQ_INSERT_TAIL(out_rules_tmp, r, entry);
break;
case IMSG_RECONF_PREFIXSET:
+ case IMSG_RECONF_ROA_SET:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(ps->name))
fatalx("IMSG_RECONF_PREFIXSET bad len");
@@ -884,9 +892,22 @@ rde_dispatch_imsg_parent(struct imsgbuf
if (ps == NULL)
fatal(NULL);
memcpy(ps->name, imsg.data, sizeof(ps->name));
- SIMPLEQ_INSERT_TAIL(prefixsets_tmp, ps, entry);
+ if (imsg.hdr.type == IMSG_RECONF_ROA_SET) {
+ SIMPLEQ_INSERT_TAIL(roasets_tmp, ps, entry);
+ ps->roa = 1;
+ last_set = set_new(1, sizeof(struct roa_set));
+ if (last_set == NULL)
+ fatal(NULL);
+ } else
+ SIMPLEQ_INSERT_TAIL(prefixsets_tmp, ps, entry);
last_prefixset = ps;
break;
+ case IMSG_RECONF_ROA_AS_SET_ITEMS:
+ nmemb = imsg.hdr.len - IMSG_HEADER_SIZE;
+ nmemb /= sizeof(struct roa_set);
+ if (set_add(last_set, imsg.data, nmemb) != 0)
+ fatal(NULL);
+ break;
case IMSG_RECONF_PREFIXSETITEM:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
sizeof(psi))
@@ -894,11 +915,19 @@ rde_dispatch_imsg_parent(struct imsgbuf
memcpy(&psi, imsg.data, sizeof(psi));
if (last_prefixset == NULL)
fatalx("King Bula has no prefixset");
- if (trie_add(&last_prefixset->th, &psi.p.addr,
- psi.p.len, psi.p.len_min, psi.p.len_max) == -1)
- log_warnx("trie_add(%s) %s/%u, %u-%u) failed",
+ if (last_prefixset->roa) {
+ set_prep(last_set);
+ rv = trie_roa_add(&last_prefixset->th,
+ &psi.p.addr, psi.p.len, last_set);
+ } else {
+ rv = trie_add(&last_prefixset->th,
+ &psi.p.addr, psi.p.len,
+ psi.p.len_min, psi.p.len_max);
+ }
+ if (rv == -1)
+ log_warnx("trie_add(%s) %s/%u) failed",
last_prefixset->name, log_addr(&psi.p.addr),
- psi.p.len, psi.p.len_min, psi.p.len_max);
+ psi.p.len);
break;
case IMSG_RECONF_AS_SET:
if (imsg.hdr.len - IMSG_HEADER_SIZE !=
@@ -2795,6 +2824,7 @@ rde_reload_done(void)
}
prefixsets_old = conf->rde_prefixsets;
+ roasets_old = conf->rde_roasets;
as_sets_old = conf->as_sets;
memcpy(conf, nconf, sizeof(struct bgpd_config));
@@ -2802,6 +2832,7 @@ rde_reload_done(void)
conf->csock = NULL;
conf->rcsock = NULL;
conf->prefixsets = NULL;
+ conf->roasets = NULL;
free(nconf);
nconf = NULL;
@@ -2826,11 +2857,15 @@ rde_reload_done(void)
/* XXX WHERE IS THE SYNC ??? */
rde_mark_prefixsets_dirty(prefixsets_old, prefixsets_tmp);
+ rde_mark_prefixsets_dirty(roasets_old, roasets_tmp);
as_sets_mark_dirty(as_sets_old, as_sets_tmp);
/* swap the prefixsets */
conf->rde_prefixsets = prefixsets_tmp;
prefixsets_tmp = NULL;
+ /* the roa-sets */
+ conf->rde_roasets = roasets_tmp;
+ roasets_tmp = NULL;
/* and the as_sets */
conf->as_sets = as_sets_tmp;
as_sets_tmp = NULL;
@@ -3022,6 +3057,8 @@ rde_softreconfig_done(void)
rde_free_prefixsets(prefixsets_old);
prefixsets_old = NULL;
+ rde_free_prefixsets(roasets_old);
+ roasets_old = NULL;
as_sets_free(as_sets_old);
as_sets_old = NULL;