From 5d45fc544b533d1c5deb531e20be61e1e3aec6e2 Mon Sep 17 00:00:00 2001 From: Claudio Jeker Date: Mon, 24 Jun 2019 06:39:50 +0000 Subject: mrt dumps lost communities after the community rewrite. Readd them by dumping them explicitly. Tested by and OK benno@ --- usr.sbin/bgpd/mrt.c | 24 ++++++--- usr.sbin/bgpd/rde.h | 21 ++++---- usr.sbin/bgpd/rde_attr.c | 4 +- usr.sbin/bgpd/rde_community.c | 117 +++++++++++++++++++++++++++++++++++++++++- 4 files changed, 145 insertions(+), 21 deletions(-) diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c index 241f59d90d1..c1d744931b0 100644 --- a/usr.sbin/bgpd/mrt.c +++ b/usr.sbin/bgpd/mrt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.c,v 1.95 2019/06/22 05:44:05 claudio Exp $ */ +/* $OpenBSD: mrt.c,v 1.96 2019/06/24 06:39:49 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker @@ -34,7 +34,8 @@ #include "mrt.h" #include "log.h" -int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct bgpd_addr *, int); +int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct rde_community *, + struct bgpd_addr *, int); int mrt_dump_entry_mp(struct mrt *, struct prefix *, u_int16_t, struct rde_peer*); int mrt_dump_entry(struct mrt *, struct prefix *, u_int16_t, struct rde_peer*); @@ -143,8 +144,8 @@ fail: } int -mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop, - int v2) +mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct rde_community *c, + struct bgpd_addr *nexthop, int v2) { struct attr *oa; u_char *pdata; @@ -188,6 +189,10 @@ mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr *nexthop, if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1) return (-1); + /* communities */ + if (community_writebuf(buf, c) == -1) + return (-1); + /* dump all other path attributes without modification */ for (l = 0; l < a->others_len; l++) { if ((oa = a->others[l]) == NULL) @@ -272,7 +277,8 @@ mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum, return (-1); } - if (mrt_attr_dump(buf, prefix_aspath(p), NULL, 0) == -1) { + if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p), + NULL, 0) == -1) { log_warnx("mrt_dump_entry_mp: mrt_attr_dump error"); goto fail; } @@ -401,7 +407,8 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, nh = &addr; } else nh = &nexthop->exit_nexthop; - if (mrt_attr_dump(buf, prefix_aspath(p), nh, 0) == -1) { + if (mrt_attr_dump(buf, prefix_aspath(p), prefix_communities(p), + nh, 0) == -1) { log_warnx("mrt_dump_entry: mrt_attr_dump error"); ibuf_free(buf); return (-1); @@ -529,7 +536,8 @@ mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, u_int32_t snum) log_warn("%s: ibuf_dynamic", __func__); return (-1); } - if (mrt_attr_dump(tbuf, prefix_aspath(p), nh, 1) == -1) { + if (mrt_attr_dump(tbuf, prefix_aspath(p), prefix_communities(p), + nh, 1) == -1) { log_warnx("%s: mrt_attr_dump error", __func__); ibuf_free(buf); return (-1); @@ -641,7 +649,7 @@ mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer) goto fail; } break; - case AID_UNSPEC: /* XXX special handling for peer_self? */ + case AID_UNSPEC: /* XXX special handling for peerself? */ DUMP_NLONG(buf, 0); break; default: diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index 30d6ffe2db6..4ed581a36e2 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.217 2019/06/22 05:44:05 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.218 2019/06/24 06:39:49 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker and @@ -395,20 +395,21 @@ u_char *aspath_override(struct aspath *, u_int32_t, u_int32_t, u_int16_t *); int aspath_lenmatch(struct aspath *, enum aslen_spec, u_int); -int community_match(struct rde_community *, struct community *, +int community_match(struct rde_community *, struct community *, struct rde_peer *); -int community_set(struct rde_community *, struct community *, +int community_set(struct rde_community *, struct community *, struct rde_peer *); -void community_delete(struct rde_community *, struct community *, +void community_delete(struct rde_community *, struct community *, struct rde_peer *); -int community_add(struct rde_community *, int, void *, size_t); -int community_large_add(struct rde_community *, int, void *, size_t); -int community_ext_add(struct rde_community *, int, void *, size_t); +int community_add(struct rde_community *, int, void *, size_t); +int community_large_add(struct rde_community *, int, void *, size_t); +int community_ext_add(struct rde_community *, int, void *, size_t); -int community_write(struct rde_community *, void *, u_int16_t); -int community_large_write(struct rde_community *, void *, u_int16_t); -int community_ext_write(struct rde_community *, int, void *, u_int16_t); +int community_write(struct rde_community *, void *, u_int16_t); +int community_large_write(struct rde_community *, void *, u_int16_t); +int community_ext_write(struct rde_community *, int, void *, u_int16_t); +int community_writebuf(struct ibuf *, struct rde_community *); void communities_init(u_int32_t); void communities_shutdown(void); diff --git a/usr.sbin/bgpd/rde_attr.c b/usr.sbin/bgpd/rde_attr.c index 95934519a1e..3aaf51bbd1a 100644 --- a/usr.sbin/bgpd/rde_attr.c +++ b/usr.sbin/bgpd/rde_attr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_attr.c,v 1.122 2019/06/17 11:02:19 claudio Exp $ */ +/* $OpenBSD: rde_attr.c,v 1.123 2019/06/24 06:39:49 claudio Exp $ */ /* * Copyright (c) 2004 Claudio Jeker @@ -86,7 +86,7 @@ attr_writebuf(struct ibuf *buf, u_int8_t flags, u_int8_t type, void *data, if (ibuf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1) return (-1); - if (ibuf_add(buf, data, data_len) == -1) + if (data && ibuf_add(buf, data, data_len) == -1) return (-1); return (0); } diff --git a/usr.sbin/bgpd/rde_community.c b/usr.sbin/bgpd/rde_community.c index 3c074fe12a8..1897c24f489 100644 --- a/usr.sbin/bgpd/rde_community.c +++ b/usr.sbin/bgpd/rde_community.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_community.c,v 1.1 2019/06/17 11:02:19 claudio Exp $ */ +/* $OpenBSD: rde_community.c,v 1.2 2019/06/24 06:39:49 claudio Exp $ */ /* * Copyright (c) 2019 Claudio Jeker @@ -606,6 +606,121 @@ community_ext_write(struct rde_community *comm, int ebgp, void *buf, return r; } +/* + * Convert communities back to the wireformat and dump them into the ibuf buf. + * This function is used by the mrt dump code. + */ +int +community_writebuf(struct ibuf *buf, struct rde_community *comm) +{ + size_t l, basic_n = 0, large_n = 0, ext_n = 0; + int flags; + + /* first count how many communities will be written */ + for (l = 0; l < comm->nentries; l++) + if ((u_int8_t)comm->communities[l].flags == + COMMUNITY_TYPE_BASIC) + basic_n++; + else if ((u_int8_t)comm->communities[l].flags == + COMMUNITY_TYPE_EXT) + ext_n++; + else if ((u_int8_t)comm->communities[l].flags == + COMMUNITY_TYPE_LARGE) + large_n++; + + + if (basic_n != 0) { + /* write attribute header */ + flags = ATTR_OPTIONAL | ATTR_TRANSITIVE; + if (comm->flags & PARTIAL_COMMUNITIES) + flags |= ATTR_PARTIAL; + + if (attr_writebuf(buf, flags, ATTR_COMMUNITIES, NULL, + basic_n * 4) == -1) + return -1; + + /* write out the communities */ + for (l = 0; l < comm->nentries; l++) + if ((u_int8_t)comm->communities[l].flags == + COMMUNITY_TYPE_BASIC) { + u_int16_t c; + c = htons(comm->communities[l].data1); + if (ibuf_add(buf, &c, sizeof(c)) == -1) + return (-1); + c = htons(comm->communities[l].data2); + if (ibuf_add(buf, &c, sizeof(c)) == -1) + return (-1); + } + } + if (ext_n != 0) { + /* write attribute header */ + flags = ATTR_OPTIONAL | ATTR_TRANSITIVE; + if (comm->flags & PARTIAL_COMMUNITIES) + flags |= ATTR_PARTIAL; + + if (attr_writebuf(buf, flags, ATTR_EXT_COMMUNITIES, NULL, + ext_n * 8) == -1) + return -1; + + /* write out the communities */ + for (l = 0; l < comm->nentries; l++) { + struct community *cp; + u_int64_t ext; + + cp = comm->communities + l; + if ((u_int8_t)cp->flags != COMMUNITY_TYPE_EXT) + continue; + + ext = (u_int64_t)cp->data3 << 48; + switch (cp->data3 >> 8) { + case EXT_COMMUNITY_TRANS_TWO_AS: + case EXT_COMMUNITY_TRANS_OPAQUE: + case EXT_COMMUNITY_TRANS_EVPN: + case EXT_COMMUNITY_NON_TRANS_OPAQUE: + ext |= ((u_int64_t)cp->data1 & 0xffff) << 32; + ext |= (u_int64_t)cp->data2; + break; + case EXT_COMMUNITY_TRANS_FOUR_AS: + case EXT_COMMUNITY_TRANS_IPV4: + ext |= (u_int64_t)cp->data1 << 16; + ext |= (u_int64_t)cp->data2 & 0xffff; + break; + } + ext = htobe64(ext); + if (ibuf_add(buf, &ext, sizeof(ext)) == -1) + return (-1); + } + } + if (large_n != 0) { + /* write attribute header */ + flags = ATTR_OPTIONAL | ATTR_TRANSITIVE; + if (comm->flags & PARTIAL_COMMUNITIES) + flags |= ATTR_PARTIAL; + + if (attr_writebuf(buf, flags, ATTR_LARGE_COMMUNITIES, NULL, + large_n * 12) == -1) + return -1; + + /* write out the communities */ + for (l = 0; l < comm->nentries; l++) + if ((u_int8_t)comm->communities[l].flags == + COMMUNITY_TYPE_LARGE) { + u_int32_t c; + c = htonl(comm->communities[l].data1); + if (ibuf_add(buf, &c, sizeof(c)) == -1) + return (-1); + c = htonl(comm->communities[l].data2); + if (ibuf_add(buf, &c, sizeof(c)) == -1) + return (-1); + c = htonl(comm->communities[l].data3); + if (ibuf_add(buf, &c, sizeof(c)) == -1) + return (-1); + } + } + + return 0; +} + /* * Global RIB cache for communities */ -- cgit v1.2.3