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);

Reply via email to