Once again I broke mrt table dumps a bit. This time by not dumping the
community data anymore. Add this back by adding the needed code in
rde_community.c and some other minor adjustments.
With this the just commited regress test passes again :)
--
:wq Claudio
Index: mrt.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/mrt.c,v
retrieving revision 1.95
diff -u -p -r1.95 mrt.c
--- mrt.c 22 Jun 2019 05:44:05 -0000 1.95
+++ mrt.c 22 Jun 2019 06:34:50 -0000
@@ -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 r
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, struc
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 p
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, struc
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 r
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:
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.217
diff -u -p -r1.217 rde.h
--- rde.h 22 Jun 2019 05:44:05 -0000 1.217
+++ rde.h 22 Jun 2019 06:34:50 -0000
@@ -395,20 +395,21 @@ u_char *aspath_override(struct aspath *
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);
Index: rde_attr.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_attr.c,v
retrieving revision 1.122
diff -u -p -r1.122 rde_attr.c
--- rde_attr.c 17 Jun 2019 11:02:19 -0000 1.122
+++ rde_attr.c 21 Jun 2019 09:45:42 -0000
@@ -86,7 +86,7 @@ attr_writebuf(struct ibuf *buf, u_int8_t
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);
}
Index: rde_community.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_community.c,v
retrieving revision 1.1
diff -u -p -r1.1 rde_community.c
--- rde_community.c 17 Jun 2019 11:02:19 -0000 1.1
+++ rde_community.c 21 Jun 2019 09:57:20 -0000
@@ -607,6 +607,121 @@ community_ext_write(struct rde_community
}
/*
+ * 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
*/
LIST_HEAD(commhead, rde_community);