This diff adds support to read MRT files using the new introduced _ADDPATH
types as defined in RFC8050. I also started adding MRT support to bgpd but
that depends on ADD-PATH itself.
There are a few gotchas, especially the MRT_DUMP_V2 RIB_GENERIC_ADDPATH
handling is different from all other RIB entry handling. This is a major
pain point for bgpd less so for the bgpctl parser.
Some MRT update dumps that can be downloaded and use ADDPATH do actually
use the BGP4MP_MESSAGE _ADDPATH variant for non-addpath enabled sessions.
The update messages can not be parsed because the NLRI encoding is incorrect.
I tested with a few RIB and UPDATE dumps from RIS, route-views and other
open collectors and it works for me.
--
:wq Claudio
Index: usr.sbin/bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.269
diff -u -p -r1.269 bgpctl.c
--- usr.sbin/bgpctl/bgpctl.c 16 Jun 2021 16:24:11 -0000 1.269
+++ usr.sbin/bgpctl/bgpctl.c 13 Jul 2021 13:20:51 -0000
@@ -470,7 +470,7 @@ show(struct imsg *imsg, struct parse_res
warnx("bad IMSG_CTL_SHOW_RIB_ATTR received");
break;
}
- output->attr(imsg->data, ilen, res->flags);
+ output->attr(imsg->data, ilen, res->flags, 0);
break;
case IMSG_CTL_SHOW_RIB_MEM:
if (imsg->hdr.len < IMSG_HEADER_SIZE + sizeof(stats))
@@ -1150,6 +1150,10 @@ show_mrt_dump(struct mrt_rib *mr, struct
ctl.local_pref = mre->local_pref;
ctl.med = mre->med;
/* weight is not part of the mrt dump so it can't be set */
+ if (mr->add_path) {
+ ctl.flags |= F_PREF_PATH_ID;
+ ctl.path_id = mre->path_id;
+ }
if (mre->peer_idx < mp->npeers) {
ctl.remote_addr = mp->peers[mre->peer_idx].addr;
@@ -1195,7 +1199,7 @@ show_mrt_dump(struct mrt_rib *mr, struct
if (req->flags & F_CTL_DETAIL) {
for (j = 0; j < mre->nattrs; j++)
output->attr(mre->attrs[j].attr,
- mre->attrs[j].attr_len, req->flags);
+ mre->attrs[j].attr_len, req->flags, 0);
}
}
}
@@ -1211,6 +1215,10 @@ network_mrt_dump(struct mrt_rib *mr, str
time_t now;
u_int16_t i, j;
+ /* can't announce more than one path so ignore add-path */
+ if (mr->add_path)
+ return;
+
now = time(NULL);
for (i = 0; i < mr->nentries; i++) {
mre = &mr->entries[i];
@@ -1586,10 +1594,11 @@ show_mrt_notification(u_char *p, u_int16
/* XXX this function does not handle JSON output */
static void
-show_mrt_update(u_char *p, u_int16_t len, int reqflags)
+show_mrt_update(u_char *p, u_int16_t len, int reqflags, int addpath)
{
struct bgpd_addr prefix;
int pos;
+ u_int32_t pathid;
u_int16_t wlen, alen;
u_int8_t prefixlen;
@@ -1609,12 +1618,25 @@ show_mrt_update(u_char *p, u_int16_t len
if (wlen > 0) {
printf("\n Withdrawn prefixes:");
while (wlen > 0) {
+ if (addpath) {
+ if (wlen <= sizeof(pathid)) {
+ printf("bad withdraw prefix");
+ return;
+ }
+ memcpy(&pathid, p, sizeof(pathid));
+ pathid = ntohl(pathid);
+ p += sizeof(pathid);
+ len -= sizeof(pathid);
+ wlen -= sizeof(pathid);
+ }
if ((pos = nlri_get_prefix(p, wlen, &prefix,
&prefixlen)) == -1) {
printf("bad withdraw prefix");
return;
}
printf(" %s/%u", log_addr(&prefix), prefixlen);
+ if (addpath)
+ printf(" path-id %u", pathid);
p += pos;
len -= pos;
wlen -= pos;
@@ -1655,7 +1677,7 @@ show_mrt_update(u_char *p, u_int16_t len
attrlen += 1 + 2;
}
- output->attr(p, attrlen, reqflags);
+ output->attr(p, attrlen, reqflags, addpath);
p += attrlen;
alen -= attrlen;
len -= attrlen;
@@ -1664,12 +1686,24 @@ show_mrt_update(u_char *p, u_int16_t len
if (len > 0) {
printf(" NLRI prefixes:");
while (len > 0) {
+ if (addpath) {
+ if (len <= sizeof(pathid)) {
+ printf(" bad nlri prefix: pathid, len
%d", len);
+ return;
+ }
+ memcpy(&pathid, p, sizeof(pathid));
+ pathid = ntohl(pathid);
+ p += sizeof(pathid);
+ len -= sizeof(pathid);
+ }
if ((pos = nlri_get_prefix(p, len, &prefix,
&prefixlen)) == -1) {
- printf("bad withdraw prefix");
+ printf(" bad nlri prefix");
return;
}
printf(" %s/%u", log_addr(&prefix), prefixlen);
+ if (addpath)
+ printf(" path-id %u", pathid);
p += pos;
len -= pos;
}
@@ -1739,7 +1773,8 @@ show_mrt_msg(struct mrt_bgp_msg *mm, voi
printf("illegal length: %u byte\n", len);
return;
}
- show_mrt_update(p, len - MSGSIZE_HEADER, req->flags);
+ show_mrt_update(p, len - MSGSIZE_HEADER, req->flags,
+ mm->add_path);
break;
case KEEPALIVE:
printf("%s ", msgtypenames[type]);
Index: usr.sbin/bgpctl/bgpctl.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.h,v
retrieving revision 1.11
diff -u -p -r1.11 bgpctl.h
--- usr.sbin/bgpctl/bgpctl.h 3 May 2021 14:01:56 -0000 1.11
+++ usr.sbin/bgpctl/bgpctl.h 13 Jul 2021 13:20:51 -0000
@@ -24,7 +24,7 @@ struct output {
void (*fib_table)(struct ktable *);
void (*nexthop)(struct ctl_show_nexthop *);
void (*interface)(struct ctl_show_interface *);
- void (*attr)(u_char *, size_t, int);
+ void (*attr)(u_char *, size_t, int, int);
void (*communities)(u_char *, size_t, struct parse_result *);
void (*rib)(struct ctl_show_rib *, u_char *, size_t,
struct parse_result *);
Index: usr.sbin/bgpctl/mrtparser.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/mrtparser.c,v
retrieving revision 1.14
diff -u -p -r1.14 mrtparser.c
--- usr.sbin/bgpctl/mrtparser.c 18 Jan 2021 12:16:09 -0000 1.14
+++ usr.sbin/bgpctl/mrtparser.c 13 Jul 2021 13:20:51 -0000
@@ -103,8 +103,10 @@ mrt_parse(int fd, struct mrt_parser *p,
struct mrt_bgp_state *s;
struct mrt_bgp_msg *m;
void *msg;
+ int addpath;
while ((msg = mrt_read_msg(fd, &h))) {
+ addpath = 0;
switch (ntohs(h.type)) {
case MSG_NULL:
case MSG_START:
@@ -163,6 +165,11 @@ mrt_parse(int fd, struct mrt_parser *p,
case MRT_DUMP_V2_RIB_IPV6_UNICAST:
case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
case MRT_DUMP_V2_RIB_GENERIC:
+ case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
+ case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH:
+ case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
+ case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH:
+ case MRT_DUMP_V2_RIB_GENERIC_ADDPATH:
if (p->dump == NULL)
break;
r = mrt_parse_v2_rib(&h, msg, verbose);
@@ -194,6 +201,10 @@ mrt_parse(int fd, struct mrt_parser *p,
case BGP4MP_MESSAGE_AS4:
case BGP4MP_MESSAGE_LOCAL:
case BGP4MP_MESSAGE_AS4_LOCAL:
+ case BGP4MP_MESSAGE_ADDPATH:
+ case BGP4MP_MESSAGE_AS4_ADDPATH:
+ case BGP4MP_MESSAGE_LOCAL_ADDPATH:
+ case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH:
if ((m = mrt_parse_msg(&h, msg, verbose))) {
if (p->message)
p->message(m, p->arg);
@@ -362,10 +373,10 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, vo
struct mrt_rib *r;
u_int8_t *b = msg;
u_int len = ntohl(hdr->length);
- u_int32_t snum;
+ u_int32_t snum, path_id = 0;
u_int16_t cnt, i, afi;
u_int8_t safi, aid;
- int ret;
+ int ret, addpath = 0;
if (len < sizeof(snum) + 1)
return NULL;
@@ -381,6 +392,10 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, vo
r->seqnum = ntohl(snum);
switch (ntohs(hdr->subtype)) {
+ case MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH:
+ case MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH:
+ r->add_path = 1;
+ /* FALLTHROUGH */
case MRT_DUMP_V2_RIB_IPV4_UNICAST:
case MRT_DUMP_V2_RIB_IPV4_MULTICAST:
/* prefix */
@@ -389,6 +404,10 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, vo
if (ret == 1)
goto fail;
break;
+ case MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH:
+ case MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH:
+ r->add_path = 1;
+ /* FALLTHROUGH */
case MRT_DUMP_V2_RIB_IPV6_UNICAST:
case MRT_DUMP_V2_RIB_IPV6_MULTICAST:
/* prefix */
@@ -397,8 +416,13 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, vo
if (ret == 1)
goto fail;
break;
+ case MRT_DUMP_V2_RIB_GENERIC_ADDPATH:
+ r->add_path = 1;
+ /* FALLTHROUGH */
case MRT_DUMP_V2_RIB_GENERIC:
/* fetch AFI/SAFI pair */
+ if (len < 3)
+ goto fail;
memcpy(&afi, b, sizeof(afi));
b += sizeof(afi);
len -= sizeof(afi);
@@ -410,6 +434,16 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, vo
if ((aid = mrt_afi2aid(afi, safi, verbose)) == AID_UNSPEC)
goto fail;
+ /* RFC8050 handling for add-path */
+ if (r->add_path) {
+ if (len < sizeof(path_id))
+ goto fail;
+ memcpy(&path_id, b, sizeof(path_id));
+ b += sizeof(path_id);
+ len -= sizeof(path_id);
+ path_id = ntohl(path_id);
+ }
+
/* prefix */
ret = mrt_extract_prefix(b, len, aid, &r->prefix,
&r->prefixlen, verbose);
@@ -453,6 +487,19 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, vo
len -= sizeof(otm);
entries[i].originated = ntohl(otm);
+ /* RFC8050 handling for add-path */
+ if (r->add_path &&
+ ntohs(hdr->subtype) != MRT_DUMP_V2_RIB_GENERIC_ADDPATH) {
+ if (len < sizeof(path_id) + sizeof(alen))
+ goto fail;
+ addpath = 0;
+ memcpy(&path_id, b, sizeof(path_id));
+ b += sizeof(path_id);
+ len -= sizeof(path_id);
+ path_id = ntohl(path_id);
+ }
+ entries[i].path_id = path_id;
+
/* attr_len */
memcpy(&alen, b, sizeof(alen));
b += sizeof(alen);
@@ -1141,7 +1188,7 @@ mrt_parse_msg(struct mrt_hdr *hdr, void
u_int len = ntohl(hdr->length);
u_int32_t sas, das, usec;
u_int16_t tmp16, afi;
- int r;
+ int r, addpath = 0;
u_int8_t aid;
t.tv_sec = ntohl(hdr->timestamp);
@@ -1156,7 +1203,12 @@ mrt_parse_msg(struct mrt_hdr *hdr, void
}
switch (ntohs(hdr->subtype)) {
+ case BGP4MP_MESSAGE_ADDPATH:
+ case BGP4MP_MESSAGE_LOCAL_ADDPATH:
+ addpath = 1;
+ /* FALLTHROUGH */
case BGP4MP_MESSAGE:
+ case BGP4MP_MESSAGE_LOCAL:
if (len < 8)
return (0);
/* source as */
@@ -1178,7 +1230,12 @@ mrt_parse_msg(struct mrt_hdr *hdr, void
len -= sizeof(tmp16);
afi = ntohs(tmp16);
break;
+ case BGP4MP_MESSAGE_AS4_ADDPATH:
+ case BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH:
+ addpath = 1;
+ /* FALLTHROUGH */
case BGP4MP_MESSAGE_AS4:
+ case BGP4MP_MESSAGE_AS4_LOCAL:
if (len < 12)
return (0);
/* source as */
@@ -1213,6 +1270,7 @@ mrt_parse_msg(struct mrt_hdr *hdr, void
m->time = t;
m->src_as = sas;
m->dst_as = das;
+ m->add_path = addpath;
if ((r = mrt_extract_addr(b, len, &m->src, aid)) == -1)
goto fail;
Index: usr.sbin/bgpctl/mrtparser.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/mrtparser.h,v
retrieving revision 1.3
diff -u -p -r1.3 mrtparser.h
--- usr.sbin/bgpctl/mrtparser.h 25 Feb 2019 11:51:58 -0000 1.3
+++ usr.sbin/bgpctl/mrtparser.h 13 Jul 2021 13:20:51 -0000
@@ -43,6 +43,7 @@ struct mrt_rib_entry {
time_t originated;
u_int32_t local_pref;
u_int32_t med;
+ u_int32_t path_id;
u_int16_t peer_idx;
u_int16_t aspath_len;
u_int16_t nattrs;
@@ -55,6 +56,7 @@ struct mrt_rib {
u_int32_t seqnum;
u_int16_t nentries;
u_int8_t prefixlen;
+ u_int8_t add_path;
};
/* data structures for the BGP4MP MESSAGE and STATE types */
@@ -75,6 +77,7 @@ struct mrt_bgp_msg {
u_int32_t src_as;
u_int32_t dst_as;
u_int16_t msg_len;
+ u_int8_t add_path;
void *msg;
};
Index: usr.sbin/bgpctl/output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
retrieving revision 1.17
diff -u -p -r1.17 output.c
--- usr.sbin/bgpctl/output.c 27 May 2021 08:29:07 -0000 1.17
+++ usr.sbin/bgpctl/output.c 13 Jul 2021 13:20:51 -0000
@@ -666,13 +666,13 @@ show_ext_community(u_char *data, u_int16
}
static void
-show_attr(u_char *data, size_t len, int reqflags)
+show_attr(u_char *data, size_t len, int reqflags, int addpath)
{
u_char *path;
struct in_addr id;
struct bgpd_addr prefix;
char *aspath;
- u_int32_t as;
+ u_int32_t as, pathid;
u_int16_t alen, ioff, short_as, afi;
u_int8_t flags, type, safi, aid, prefixlen;
int i, pos, e2, e4;
@@ -851,6 +851,16 @@ show_attr(u_char *data, size_t len, int
}
while (alen > 0) {
+ if (addpath) {
+ if (alen <= sizeof(pathid)) {
+ printf("bad nlri prefix");
+ return;
+ }
+ memcpy(&pathid, data, sizeof(pathid));
+ pathid = ntohl(pathid);
+ data += sizeof(pathid);
+ alen -= sizeof(pathid);
+ }
switch (aid) {
case AID_INET6:
pos = nlri_get_prefix6(data, alen, &prefix,
@@ -873,6 +883,8 @@ show_attr(u_char *data, size_t len, int
break;
}
printf(" %s/%u", log_addr(&prefix), prefixlen);
+ if (addpath)
+ printf(" path-id %u", pathid);
data += pos;
alen -= pos;
}
@@ -940,7 +952,10 @@ show_rib_detail(struct ctl_show_rib *r,
printf("(via %s) Neighbor %s (", log_addr(&r->true_nexthop), s);
free(s);
id.s_addr = htonl(r->remote_id);
- printf("%s)%c", inet_ntoa(id), EOL0(flag0));
+
+ if (r->flags & F_PREF_PATH_ID)
+ printf("%s) Path-Id: %u%c", inet_ntoa(id), r->path_id,
+ EOL0(flag0));
printf(" Origin %s, metric %u, localpref %u, weight %u, ovs %s, ",
fmt_origin(r->origin, 0), r->med, r->local_pref, r->weight,
Index: usr.sbin/bgpctl/output_json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v
retrieving revision 1.11
diff -u -p -r1.11 output_json.c
--- usr.sbin/bgpctl/output_json.c 27 May 2021 08:29:07 -0000 1.11
+++ usr.sbin/bgpctl/output_json.c 13 Jul 2021 13:20:51 -0000
@@ -586,13 +586,13 @@ json_do_ext_community(u_char *data, uint
}
static void
-json_attr(u_char *data, size_t len, int reqflags)
+json_attr(u_char *data, size_t len, int reqflags, int addpath)
{
struct bgpd_addr prefix;
struct in_addr id;
char *aspath;
u_char *path;
- uint32_t as;
+ uint32_t as, pathid;
uint16_t alen, afi, off, short_as;
uint8_t flags, type, safi, aid, prefixlen;
int e4, e2, pos;
@@ -783,6 +783,17 @@ bad_len:
json_do_array("NLRI");
while (alen > 0) {
+ json_do_object("prefix");
+ if (addpath) {
+ if (alen <= sizeof(pathid)) {
+ json_do_printf("error", "bad path-id");
+ break;
+ }
+ memcpy(&pathid, data, sizeof(pathid));
+ pathid = ntohl(pathid);
+ data += sizeof(pathid);
+ alen -= sizeof(pathid);
+ }
switch (aid) {
case AID_INET6:
pos = nlri_get_prefix6(data, alen, &prefix,
@@ -808,9 +819,13 @@ bad_len:
}
json_do_printf("prefix", "%s/%u", log_addr(&prefix),
prefixlen);
+ if (addpath)
+ json_do_uint("path_id", pathid);
data += pos;
alen -= pos;
+ json_do_end();
}
+ json_do_end();
break;
case ATTR_EXT_COMMUNITIES:
json_do_ext_community(data, alen);
@@ -854,6 +869,9 @@ json_rib(struct ctl_show_rib *r, u_char
id.s_addr = htonl(r->remote_id);
json_do_printf("bgp_id", "%s", inet_ntoa(id));
json_do_end();
+
+ if (r->flags & F_PREF_PATH_ID)
+ json_do_uint("path_id", r->path_id);
/* flags */
json_do_bool("valid", r->flags & F_PREF_ELIGIBLE);
Index: usr.sbin/bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.415
diff -u -p -r1.415 bgpd.h
--- usr.sbin/bgpd/bgpd.h 17 Jun 2021 16:05:26 -0000 1.415
+++ usr.sbin/bgpd/bgpd.h 13 Jul 2021 13:20:51 -0000
@@ -791,6 +791,7 @@ struct ctl_neighbor {
#define F_PREF_ANNOUNCE 0x08
#define F_PREF_STALE 0x10
#define F_PREF_INVALID 0x20
+#define F_PREF_PATH_ID 0x40
struct ctl_show_rib {
struct bgpd_addr true_nexthop;
@@ -800,6 +801,7 @@ struct ctl_show_rib {
char descr[PEER_DESCR_LEN];
time_t age;
u_int32_t remote_id;
+ u_int32_t path_id;
u_int32_t local_pref;
u_int32_t med;
u_int32_t weight;
Index: usr.sbin/bgpd/mrt.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/mrt.h,v
retrieving revision 1.35
diff -u -p -r1.35 mrt.h
--- usr.sbin/bgpd/mrt.h 31 Dec 2019 15:09:40 -0000 1.35
+++ usr.sbin/bgpd/mrt.h 13 Jul 2021 13:20:51 -0000
@@ -84,7 +84,11 @@ enum MRT_BGP4MP_SUBTYPES {
BGP4MP_MESSAGE_AS4, /* same as BGP4MP_MESSAGE with 4byte AS */
BGP4MP_STATE_CHANGE_AS4,
BGP4MP_MESSAGE_LOCAL, /* same as BGP4MP_MESSAGE but for self */
- BGP4MP_MESSAGE_AS4_LOCAL /* originated updates. Not implemented */
+ BGP4MP_MESSAGE_AS4_LOCAL, /* originated updates. Not implemented */
+ BGP4MP_MESSAGE_ADDPATH, /* same as above but for add-path peers */
+ BGP4MP_MESSAGE_AS4_ADDPATH,
+ BGP4MP_MESSAGE_LOCAL_ADDPATH,
+ BGP4MP_MESSAGE_AS4_LOCAL_ADDPATH,
};
/* size of the BGP4MP headers without payload */
@@ -178,7 +182,12 @@ enum MRT_DUMP_V2_SUBTYPES {
MRT_DUMP_V2_RIB_IPV4_MULTICAST=3,
MRT_DUMP_V2_RIB_IPV6_UNICAST=4,
MRT_DUMP_V2_RIB_IPV6_MULTICAST=5,
- MRT_DUMP_V2_RIB_GENERIC=6
+ MRT_DUMP_V2_RIB_GENERIC=6,
+ MRT_DUMP_V2_RIB_IPV4_UNICAST_ADDPATH=8,
+ MRT_DUMP_V2_RIB_IPV4_MULTICAST_ADDPATH=9,
+ MRT_DUMP_V2_RIB_IPV6_UNICAST_ADDPATH=10,
+ MRT_DUMP_V2_RIB_IPV6_MULTICAST_ADDPATH=11,
+ MRT_DUMP_V2_RIB_GENERIC_ADDPATH=12,
};
/*
@@ -228,7 +237,7 @@ enum MRT_DUMP_V2_SUBTYPES {
* | #entry | rib entries (variable)
* +--------+--------+--------+--------+
*
- * The RIB_GENERIC subtype is needed for the less common AFI/SAFI pairs
+ * The RIB_GENERIC subtype is needed for the less common AFI/SAFI pairs.
*
* +--------+--------+--------+--------+
* | seq_num |
@@ -249,6 +258,8 @@ enum MRT_DUMP_V2_SUBTYPES {
* +--------+--------+--------+--------+
* | originated_time |
* +--------+--------+--------+--------+
+ * [ path_id in _ADDPATH variants ]
+ * +--------+--------+--------+--------+
* | attr_len | bgp_attrs
* +--------+--------+--------+--------+
* bgp_attrs (variable) ...
@@ -257,6 +268,10 @@ enum MRT_DUMP_V2_SUBTYPES {
* Some BGP path attributes need special encoding:
* - the AS_PATH attribute MUST be encoded as 4-Byte AS
* - the MP_REACH_NLRI only consists of the nexthop len and nexthop address
+ *
+ * The non generic ADDPATH variants add the path-identifier between
+ * originated_time and attr_len. For RIB_GENERIC_ADDPATH the path_id should
+ * be part of the NLRI.
*/
/*