From: claudio Date: Tue, 27 Jul 2021 07:42:37 +0000 (+0000) Subject: Implemnt the RFC8050 in the MRT parser. With this MRT dumps containing X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=9e59dee7d2e6917372df111a92048421eb4e0fdf;p=openbsd Implemnt the RFC8050 in the MRT parser. With this MRT dumps containing 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@ --- diff --git a/usr.sbin/bgpctl/bgpctl.c b/usr.sbin/bgpctl/bgpctl.c index 8386f0b4cc2..f50ef36d2df 100644 --- a/usr.sbin/bgpctl/bgpctl.c +++ b/usr.sbin/bgpctl/bgpctl.c @@ -1,4 +1,4 @@ -/* $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 @@ -470,7 +470,7 @@ show(struct imsg *imsg, struct parse_result *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 mrt_peer *mp, void *arg) 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 mrt_peer *mp, void *arg) 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, struct mrt_peer *mp, void *arg) 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_t len) /* 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, int reqflags) 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, int reqflags) 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, int reqflags) 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, void *arg) 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]); diff --git a/usr.sbin/bgpctl/bgpctl.h b/usr.sbin/bgpctl/bgpctl.h index cf544df9ae2..6ccdf4ba35d 100644 --- a/usr.sbin/bgpctl/bgpctl.h +++ b/usr.sbin/bgpctl/bgpctl.h @@ -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 *); diff --git a/usr.sbin/bgpctl/mrtparser.c b/usr.sbin/bgpctl/mrtparser.c index 822e64e1e3a..3297ed56bad 100644 --- a/usr.sbin/bgpctl/mrtparser.c +++ b/usr.sbin/bgpctl/mrtparser.c @@ -1,4 +1,4 @@ -/* $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 * @@ -103,8 +103,10 @@ mrt_parse(int fd, struct mrt_parser *p, int verbose) 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, int verbose) 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, int 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); @@ -362,10 +373,10 @@ mrt_parse_v2_rib(struct mrt_hdr *hdr, void *msg, int verbose) 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, void *msg, int verbose) 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, void *msg, int verbose) 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, void *msg, int verbose) 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, void *msg, int verbose) 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, void *msg, int 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); @@ -1141,7 +1188,7 @@ mrt_parse_msg(struct mrt_hdr *hdr, void *msg, int verbose) 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 *msg, int verbose) } 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 *msg, int verbose) 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 *msg, int verbose) 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; diff --git a/usr.sbin/bgpctl/mrtparser.h b/usr.sbin/bgpctl/mrtparser.h index 7da4d62f2f8..4a1b2e9e35f 100644 --- a/usr.sbin/bgpctl/mrtparser.h +++ b/usr.sbin/bgpctl/mrtparser.h @@ -1,4 +1,4 @@ -/* $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 * @@ -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; }; diff --git a/usr.sbin/bgpctl/output.c b/usr.sbin/bgpctl/output.c index f817c715ce8..6d2f8461e39 100644 --- a/usr.sbin/bgpctl/output.c +++ b/usr.sbin/bgpctl/output.c @@ -1,4 +1,4 @@ -/* $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 @@ -666,13 +666,13 @@ show_ext_community(u_char *data, u_int16_t len) } 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 reqflags) } 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 reqflags) 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, u_char *asdata, size_t aslen, 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, diff --git a/usr.sbin/bgpctl/output_json.c b/usr.sbin/bgpctl/output_json.c index 03e7025f7c6..8a0441ba551 100644 --- a/usr.sbin/bgpctl/output_json.c +++ b/usr.sbin/bgpctl/output_json.c @@ -1,4 +1,4 @@ -/* $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 @@ -586,13 +586,13 @@ json_do_ext_community(u_char *data, uint16_t len) } 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); @@ -855,6 +870,9 @@ json_rib(struct ctl_show_rib *r, u_char *asdata, size_t aslen, 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)