The use of roa-set, prefix-set and as-set is fairly common in bgpd.
Still sometimes it is not exactly clear how old the data in those tables
is. This diff is a first step at inproving inspection by adding
bgpctl show sets
Sample output is:
Type Name #IPv4 #Ipv6 #ASnum Last Change
ROA RPKI ROA 158810 26257 - 00:00:07
ASNUM asns_AS15600 - - 26 01:19:10
PREFIX p4_AS21040 8 0 - 01:19:10
I just did a bgpctl reload with a new roa table (generated by rpki-client)
but the as-set and prefix-set did not change during this reload.
The output also includes the number of entries in the tables but in the
case of roa-set the number of unique prefixes is counted. So the number is
a bit under the count from rpki-client because e.g.
1.32.219.0/24 source-as 4842
1.32.219.0/24 source-as 138570
are counted as 1 right now (instead of 2 prefixes).
More statistics can be added if their calculation is easy.
--
:wq Claudio
PS: apply diff in /usr/src/usr.sbin
Index: bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.405
diff -u -p -r1.405 bgpd.h
--- bgpd/bgpd.h 5 Nov 2020 11:52:59 -0000 1.405
+++ bgpd/bgpd.h 3 Dec 2020 20:15:30 -0000
@@ -254,12 +254,15 @@ struct trie_head {
struct tentry_v6 *root_v6;
int match_default_v4;
int match_default_v6;
+ size_t v4_cnt;
+ size_t v6_cnt;
};
struct rde_prefixset {
char name[SET_NAME_LEN];
struct trie_head th;
SIMPLEQ_ENTRY(rde_prefixset) entry;
+ time_t lastchange;
int dirty;
};
SIMPLEQ_HEAD(rde_prefixset_head, rde_prefixset);
@@ -465,6 +468,7 @@ enum imsg_type {
IMSG_CTL_SHOW_TIMER,
IMSG_CTL_LOG_VERBOSE,
IMSG_CTL_SHOW_FIB_TABLES,
+ IMSG_CTL_SHOW_SET,
IMSG_CTL_TERMINATE,
IMSG_NETWORK_ADD,
IMSG_NETWORK_ASPATH,
@@ -696,6 +700,20 @@ struct ctl_show_nexthop {
u_int8_t krvalid;
};
+struct ctl_show_set {
+ char name[SET_NAME_LEN];
+ time_t lastchange;
+ size_t v4_cnt;
+ size_t v6_cnt;
+ size_t as_cnt;
+ enum {
+ ASNUM_SET,
+ PREFIX_SET,
+ ORIGIN_SET,
+ ROA_SET,
+ } type;
+};
+
struct ctl_neighbor {
struct bgpd_addr addr;
char descr[PEER_DESCR_LEN];
@@ -1049,6 +1067,7 @@ struct as_set {
char name[SET_NAME_LEN];
SIMPLEQ_ENTRY(as_set) entry;
struct set_table *set;
+ time_t lastchange;
int dirty;
};
@@ -1283,6 +1302,7 @@ void set_prep(struct set_table *);
void *set_match(const struct set_table *, u_int32_t);
int set_equal(const struct set_table *,
const struct set_table *);
+size_t set_nmemb(const struct set_table *);
/* rde_trie.c */
int trie_add(struct trie_head *, struct bgpd_addr *, u_int8_t, u_int8_t,
Index: bgpd/control.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/control.c,v
retrieving revision 1.101
diff -u -p -r1.101 control.c
--- bgpd/control.c 5 Nov 2020 11:28:11 -0000 1.101
+++ bgpd/control.c 3 Dec 2020 17:07:58 -0000
@@ -280,6 +280,7 @@ control_dispatch_msg(struct pollfd *pfd,
case IMSG_CTL_SHOW_NETWORK:
case IMSG_CTL_SHOW_RIB:
case IMSG_CTL_SHOW_RIB_PREFIX:
+ case IMSG_CTL_SHOW_SET:
break;
default:
/* clear imsg type to prevent processing */
@@ -496,6 +497,7 @@ control_dispatch_msg(struct pollfd *pfd,
c->terminate = 1;
/* FALLTHROUGH */
case IMSG_CTL_SHOW_RIB_MEM:
+ case IMSG_CTL_SHOW_SET:
c->ibuf.pid = imsg.hdr.pid;
imsg_ctl_rde(imsg.hdr.type, imsg.hdr.pid,
imsg.data, imsg.hdr.len - IMSG_HEADER_SIZE);
Index: bgpd/rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.506
diff -u -p -r1.506 rde.c
--- bgpd/rde.c 5 Nov 2020 14:44:59 -0000 1.506
+++ bgpd/rde.c 3 Dec 2020 20:16:06 -0000
@@ -342,12 +342,15 @@ rde_dispatch_imsg_session(struct imsgbuf
struct imsg imsg;
struct peer p;
struct peer_config pconf;
+ struct ctl_show_set cset;
struct ctl_show_rib csr;
struct ctl_show_rib_request req;
struct rde_peer *peer;
struct rde_aspath *asp;
struct rde_hashstats rdehash;
struct filter_set *s;
+ struct as_set *aset;
+ struct rde_prefixset *pset;
u_int8_t *asdata;
ssize_t n;
size_t aslen;
@@ -571,6 +574,53 @@ badnetdel:
imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, imsg.hdr.pid,
-1, NULL, 0);
break;
+ case IMSG_CTL_SHOW_SET:
+ /* first roa set */
+ pset = &conf->rde_roa;
+ memset(&cset, 0, sizeof(cset));
+ cset.type = ROA_SET;
+ strlcpy(cset.name, "RPKI ROA", sizeof(cset.name));
+ cset.lastchange = pset->lastchange;
+ cset.v4_cnt = pset->th.v4_cnt;
+ cset.v6_cnt = pset->th.v6_cnt;
+ imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
+ imsg.hdr.pid, -1, &cset, sizeof(cset));
+
+ SIMPLEQ_FOREACH(aset, &conf->as_sets, entry) {
+ memset(&cset, 0, sizeof(cset));
+ cset.type = ASNUM_SET;
+ strlcpy(cset.name, aset->name,
+ sizeof(cset.name));
+ cset.lastchange = aset->lastchange;
+ cset.as_cnt = set_nmemb(aset->set);
+ imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
+ imsg.hdr.pid, -1, &cset, sizeof(cset));
+ }
+ SIMPLEQ_FOREACH(pset, &conf->rde_prefixsets, entry) {
+ memset(&cset, 0, sizeof(cset));
+ cset.type = PREFIX_SET;
+ strlcpy(cset.name, pset->name,
+ sizeof(cset.name));
+ cset.lastchange = pset->lastchange;
+ cset.v4_cnt = pset->th.v4_cnt;
+ cset.v6_cnt = pset->th.v6_cnt;
+ imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
+ imsg.hdr.pid, -1, &cset, sizeof(cset));
+ }
+ SIMPLEQ_FOREACH(pset, &conf->rde_originsets, entry) {
+ memset(&cset, 0, sizeof(cset));
+ cset.type = ORIGIN_SET;
+ strlcpy(cset.name, pset->name,
+ sizeof(cset.name));
+ cset.lastchange = pset->lastchange;
+ cset.v4_cnt = pset->th.v4_cnt;
+ cset.v6_cnt = pset->th.v6_cnt;
+ imsg_compose(ibuf_se_ctl, IMSG_CTL_SHOW_SET, 0,
+ imsg.hdr.pid, -1, &cset, sizeof(cset));
+ }
+ imsg_compose(ibuf_se_ctl, IMSG_CTL_END, 0, imsg.hdr.pid,
+ -1, NULL, 0);
+ break;
case IMSG_CTL_LOG_VERBOSE:
/* already checked by SE */
memcpy(&verbose, imsg.data, sizeof(verbose));
@@ -3046,6 +3096,7 @@ rde_reload_done(void)
SIMPLEQ_CONCAT(&conf->as_sets, &nconf->as_sets);
conf->rde_roa = nconf->rde_roa;
+ conf->rde_roa.lastchange = roa_old.lastchange;
memset(&nconf->rde_roa, 0, sizeof(nconf->rde_roa));
/* apply new set of l3vpn, sync will be done later */
@@ -3069,8 +3120,10 @@ rde_reload_done(void)
if (trie_equal(&conf->rde_roa.th, &roa_old.th) == 0) {
log_debug("roa change: reloading Adj-RIB-In");
conf->rde_roa.dirty = 1;
+ conf->rde_roa.lastchange = getmonotime();
reload++; /* run softreconf in */
}
+
trie_free(&roa_old.th); /* old roa no longer needed */
rde_mark_prefixsets_dirty(&prefixsets_old, &conf->rde_prefixsets);
@@ -3809,9 +3862,13 @@ rde_mark_prefixsets_dirty(struct rde_pre
if ((psold == NULL) ||
(old = rde_find_prefixset(new->name, psold)) == NULL) {
new->dirty = 1;
+ new->lastchange = getmonotime();
} else {
- if (trie_equal(&new->th, &old->th) == 0)
+ if (trie_equal(&new->th, &old->th) == 0) {
new->dirty = 1;
+ new->lastchange = getmonotime();
+ } else
+ new->lastchange = old->lastchange;
}
}
}
Index: bgpd/rde_sets.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_sets.c,v
retrieving revision 1.9
diff -u -p -r1.9 rde_sets.c
--- bgpd/rde_sets.c 5 Aug 2019 08:46:55 -0000 1.9
+++ bgpd/rde_sets.c 3 Dec 2020 16:36:15 -0000
@@ -93,8 +93,11 @@ as_sets_mark_dirty(struct as_set_head *o
SIMPLEQ_FOREACH(n, new, entry) {
if (old == NULL || (o = as_sets_lookup(old, n->name)) == NULL ||
- !set_equal(n->set, o->set))
+ !set_equal(n->set, o->set)) {
n->dirty = 1;
+ n->lastchange = getmonotime();
+ } else
+ n->lastchange = o->lastchange;
}
}
@@ -223,4 +226,10 @@ set_equal(const struct set_table *a, con
if (memcmp(a->set, b->set, a->nmemb * a->size) != 0)
return 0;
return 1;
+}
+
+size_t
+set_nmemb(const struct set_table *set)
+{
+ return set->nmemb;
}
Index: bgpd/rde_trie.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_trie.c,v
retrieving revision 1.10
diff -u -p -r1.10 rde_trie.c
--- bgpd/rde_trie.c 26 Oct 2018 16:53:55 -0000 1.10
+++ bgpd/rde_trie.c 3 Dec 2020 15:25:38 -0000
@@ -189,6 +189,8 @@ trie_add_v4(struct trie_head *th, struct
if (n->plen == plen) {
/* matching node, adjust */
+ if (n->node == 0)
+ th->v4_cnt++;
n->node = 1;
return n;
}
@@ -204,6 +206,7 @@ trie_add_v4(struct trie_head *th, struct
/* create new node */
if ((new = calloc(1, sizeof(*new))) == NULL)
return NULL;
+ th->v4_cnt++;
rdemem.pset_cnt++;
rdemem.pset_size += sizeof(*new);
new->addr = p;
@@ -269,6 +272,8 @@ trie_add_v6(struct trie_head *th, struct
if (n->plen == plen) {
/* matching node, adjust */
+ if (n->node == 0)
+ th->v6_cnt++;
n->node = 1;
return n;
}
@@ -284,6 +289,7 @@ trie_add_v6(struct trie_head *th, struct
/* create new node */
if ((new = calloc(1, sizeof(*new))) == NULL)
return NULL;
+ th->v6_cnt++;
rdemem.pset_cnt++;
rdemem.pset_size += sizeof(*new);
new->addr = p;
Index: bgpd/session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.405
diff -u -p -r1.405 session.c
--- bgpd/session.c 5 Nov 2020 14:44:59 -0000 1.405
+++ bgpd/session.c 3 Dec 2020 17:08:29 -0000
@@ -2816,6 +2816,7 @@ session_dispatch_imsg(struct imsgbuf *ib
case IMSG_CTL_SHOW_RIB_HASH:
case IMSG_CTL_SHOW_NETWORK:
case IMSG_CTL_SHOW_NEIGHBOR:
+ case IMSG_CTL_SHOW_SET:
if (idx != PFD_PIPE_ROUTE_CTL)
fatalx("ctl rib request not from RDE");
control_imsg_relay(&imsg);
Index: bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.263
diff -u -p -r1.263 bgpctl.c
--- bgpctl/bgpctl.c 10 May 2020 13:38:46 -0000 1.263
+++ bgpctl/bgpctl.c 3 Dec 2020 20:17:14 -0000
@@ -213,6 +213,9 @@ main(int argc, char *argv[])
case SHOW_INTERFACE:
imsg_compose(ibuf, IMSG_CTL_SHOW_INTERFACE, 0, 0, -1, NULL, 0);
break;
+ case SHOW_SET:
+ imsg_compose(ibuf, IMSG_CTL_SHOW_SET, 0, 0, -1, NULL, 0);
+ break;
case SHOW_NEIGHBOR:
case SHOW_NEIGHBOR_TIMERS:
case SHOW_NEIGHBOR_TERSE:
@@ -393,6 +396,7 @@ show(struct imsg *imsg, struct parse_res
struct ctl_timer *t;
struct ctl_show_interface *iface;
struct ctl_show_nexthop *nh;
+ struct ctl_show_set *set;
struct kroute_full *kf;
struct ktable *kt;
struct ctl_show_rib rib;
@@ -466,6 +470,10 @@ show(struct imsg *imsg, struct parse_res
memcpy(&hash, imsg->data, sizeof(hash));
output->rib_hash(&hash);
break;
+ case IMSG_CTL_SHOW_SET:
+ set = imsg->data;
+ output->set(set);
+ break;
case IMSG_CTL_RESULT:
if (imsg->hdr.len != IMSG_HEADER_SIZE + sizeof(rescode)) {
warnx("got IMSG_CTL_RESULT with wrong len");
@@ -974,6 +982,23 @@ fmt_ext_community(u_int8_t *data)
log_ext_subtype(type, subtype),
(unsigned long long)be64toh(ext));
return buf;
+ }
+}
+
+const char *
+fmt_set_type(struct ctl_show_set *set)
+{
+ switch (set->type) {
+ case ROA_SET:
+ return "ROA";
+ case PREFIX_SET:
+ return "PREFIX";
+ case ORIGIN_SET:
+ return "ORIGIN";
+ case ASNUM_SET:
+ return "ASNUM";
+ default:
+ return "BULA";
}
}
Index: bgpctl/bgpctl.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.h,v
retrieving revision 1.7
diff -u -p -r1.7 bgpctl.h
--- bgpctl/bgpctl.h 2 May 2020 14:33:33 -0000 1.7
+++ bgpctl/bgpctl.h 3 Dec 2020 20:12:34 -0000
@@ -30,6 +30,7 @@ struct output {
struct parse_result *);
void (*rib_hash)(struct rde_hashstats *);
void (*rib_mem)(struct rde_memstats *);
+ void (*set)(struct ctl_show_set *);
void (*result)(u_int);
void (*tail)(void);
};
@@ -53,3 +54,4 @@ const char *fmt_attr(u_int8_t, int);
const char *fmt_community(u_int16_t, u_int16_t);
const char *fmt_large_community(u_int32_t, u_int32_t, u_int32_t);
const char *fmt_ext_community(u_int8_t *);
+const char *fmt_set_type(struct ctl_show_set *);
Index: bgpctl/output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
retrieving revision 1.10
diff -u -p -r1.10 output.c
--- bgpctl/output.c 21 Oct 2020 06:52:45 -0000 1.10
+++ bgpctl/output.c 3 Dec 2020 20:53:36 -0000
@@ -77,6 +77,10 @@ show_head(struct parse_result *res)
"flags", "ovs", "destination", "gateway", "lpref", "med",
"aspath origin");
break;
+ case SHOW_SET:
+ printf("%-6s %-34s %7s %7s %6s %11s\n", "Type", "Name",
+ "#IPv4", "#IPv6", "#ASnum", "Last Change");
+ break;
case NETWORK_SHOW:
printf("flags: S = Static\n");
printf("flags prio destination gateway\n");
@@ -958,6 +962,22 @@ show_rib_hash(struct rde_hashstats *hash
}
static void
+show_rib_set(struct ctl_show_set *set)
+{
+ char buf[64];
+
+ if (set->type == ASNUM_SET)
+ snprintf(buf, sizeof(buf), "%7s %7s %6zu",
+ "-", "-", set->as_cnt);
+ else
+ snprintf(buf, sizeof(buf), "%7zu %7zu %6s",
+ set->v4_cnt, set->v6_cnt, "-");
+
+ printf("%-6s %-34s %s %11s\n", fmt_set_type(set), set->name,
+ buf, fmt_monotime(set->lastchange));
+}
+
+static void
show_result(u_int rescode)
{
if (rescode == 0)
@@ -988,6 +1008,7 @@ const struct output show_output = {
.rib = show_rib,
.rib_mem = show_rib_mem,
.rib_hash = show_rib_hash,
+ .set = show_rib_set,
.result = show_result,
.tail = show_tail
};
Index: bgpctl/output_json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v
retrieving revision 1.4
diff -u -p -r1.4 output_json.c
--- bgpctl/output_json.c 21 Oct 2020 06:52:45 -0000 1.4
+++ bgpctl/output_json.c 3 Dec 2020 20:16:25 -0000
@@ -919,6 +919,24 @@ json_rib_hash(struct rde_hashstats *hash
}
static void
+json_rib_set(struct ctl_show_set *set)
+{
+ json_do_array("sets");
+
+ json_do_object("set");
+ json_do_printf("name", "%s", set->name);
+ json_do_printf("type", "%s", fmt_set_type(set));
+ json_do_printf("last_change", "%s", fmt_monotime(set->lastchange));
+ if (set->type == ASNUM_SET) {
+ json_do_uint("num_ASnum", set->as_cnt);
+ } else {
+ json_do_uint("num_IPv4", set->v4_cnt);
+ json_do_uint("num_IPv6", set->v6_cnt);
+ }
+ json_do_end();
+}
+
+static void
json_result(u_int rescode)
{
if (rescode == 0)
@@ -952,6 +970,7 @@ const struct output json_output = {
.rib = json_rib,
.rib_mem = json_rib_mem,
.rib_hash = json_rib_hash,
+ .set = json_rib_set,
.result = json_result,
.tail = json_tail
};
Index: bgpctl/parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.c,v
retrieving revision 1.104
diff -u -p -r1.104 parser.c
--- bgpctl/parser.c 12 May 2020 13:26:02 -0000 1.104
+++ bgpctl/parser.c 3 Dec 2020 16:52:10 -0000
@@ -136,6 +136,7 @@ static const struct token t_show[] = {
{ KEYWORD, "tables", SHOW_FIB_TABLES, NULL},
{ KEYWORD, "ip", NONE, t_show_ip},
{ KEYWORD, "summary", SHOW_SUMMARY, t_show_summary},
+ { KEYWORD, "sets", SHOW_SET, NULL},
{ KEYWORD, "mrt", SHOW_MRT, t_show_mrt},
{ ENDTOKEN, "", NONE, NULL}
};
Index: bgpctl/parser.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/parser.h,v
retrieving revision 1.38
diff -u -p -r1.38 parser.h
--- bgpctl/parser.h 10 May 2020 13:38:46 -0000 1.38
+++ bgpctl/parser.h 3 Dec 2020 16:52:22 -0000
@@ -32,6 +32,7 @@ enum actions {
SHOW_FIB_TABLES,
SHOW_RIB,
SHOW_MRT,
+ SHOW_SET,
SHOW_RIB_MEM,
SHOW_NEXTHOP,
SHOW_INTERFACE,