add-path information will be dumped properly.
There is one bit where this implementation is not in line with the RFC.
The encoding of DUMP_V2_RIB_GENERIC_ADDPATH for non IPv4 or IPv6 prefixes
is implemented the way gobgp did it (which seems to be the only other BGP
implementation that supports generic encoding). The RFC puts the path_id
in the NLRI for generic encoding instead of adding it to RIB entry struct
like in the IPv4 and IPv6 encoding. This is an open discussion point with
the RFC author.
OK benno@
-/* $OpenBSD: bgpctl.c,v 1.270 2021/07/20 12:08:53 claudio Exp $ */
+/* $OpenBSD: bgpctl.c,v 1.271 2021/07/27 07:42:37 claudio Exp $ */
/*
* Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
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))
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;
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);
}
}
}
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];
/* 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;
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;
attrlen += 1 + 2;
}
- output->attr(p, attrlen, reqflags);
+ output->attr(p, attrlen, reqflags, addpath);
p += attrlen;
alen -= attrlen;
len -= attrlen;
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;
}
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]);
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 *);
-/* $OpenBSD: mrtparser.c,v 1.14 2021/01/18 12:16:09 claudio Exp $ */
+/* $OpenBSD: mrtparser.c,v 1.15 2021/07/27 07:42:37 claudio Exp $ */
/*
* Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
*
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:
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);
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);
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;
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 */
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 */
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);
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);
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);
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);
}
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 */
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 */
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;
-/* $OpenBSD: mrtparser.h,v 1.3 2019/02/25 11:51:58 claudio Exp $ */
+/* $OpenBSD: mrtparser.h,v 1.4 2021/07/27 07:42:37 claudio Exp $ */
/*
* Copyright (c) 2011 Claudio Jeker <claudio@openbsd.org>
*
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;
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 */
u_int32_t src_as;
u_int32_t dst_as;
u_int16_t msg_len;
+ u_int8_t add_path;
void *msg;
};
-/* $OpenBSD: output.c,v 1.17 2021/05/27 08:29:07 claudio Exp $ */
+/* $OpenBSD: output.c,v 1.18 2021/07/27 07:42:37 claudio Exp $ */
/*
* Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
}
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;
}
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,
break;
}
printf(" %s/%u", log_addr(&prefix), prefixlen);
+ if (addpath)
+ printf(" path-id %u", pathid);
data += pos;
alen -= pos;
}
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,
-/* $OpenBSD: output_json.c,v 1.11 2021/05/27 08:29:07 claudio Exp $ */
+/* $OpenBSD: output_json.c,v 1.12 2021/07/27 07:42:37 claudio Exp $ */
/*
* Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
}
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;
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,
}
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);
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);
if (r->flags & F_PREF_ACTIVE)