This is an update to the MRT dump code to implement the
new table dump format specified in draft-ietf-grow-mrt-17.
The older formats should still work as before.

OK?
-- 
:wq Claudio

Index: bgpd.8
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.8,v
retrieving revision 1.39
diff -u -p -r1.39 bgpd.8
--- bgpd.8      15 Oct 2010 07:45:32 -0000      1.39
+++ bgpd.8      17 Sep 2011 15:52:20 -0000
@@ -212,9 +212,14 @@ control socket
 .%D April 2009
 .Re
 .Rs
-.%R draft-ietf-idr-fsm-subcode-00
+.%R draft-ietf-idr-fsm-subcode-02
 .%T "Subcodes for BGP Finite State Machine Error"
-.%D September 2010
+.%D August 2011
+.Re
+.Rs
+.%R draft-ietf-grow-mrt-17
+.%T "MRT routing information export format"
+.%D August 2011
 .Re
 .Sh HISTORY
 The
Index: bgpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
retrieving revision 1.115
diff -u -p -r1.115 bgpd.conf.5
--- bgpd.conf.5 23 Jun 2011 20:35:22 -0000      1.115
+++ bgpd.conf.5 17 Sep 2011 15:46:37 -0000
@@ -149,7 +149,7 @@ The default is 120 seconds.
 .It Xo
 .Ic dump
 .Op Ic rib Ar name
-.Pq Ic table Ns | Ns Ic table-mp
+.Pq Ic table Ns | Ns Ic table-mp Ns | Ns Ic table-v2
 .Ar file Op Ar timeout
 .Xc
 .It Xo
@@ -161,17 +161,21 @@ The default is 120 seconds.
 Dump the RIB, a.k.a. the
 .Em routing information base ,
 and all BGP messages in Multi-threaded Routing Toolkit (MRT) format.
-Dumping the RIB is normally an expensive operation,
-but it should not influence the session handling.
 It is possible to dump alternate RIB with the use of
 .Ar name .
 .Pp
 For example, the following will dump the entire table to the
 .Xr strftime 3 Ns -expanded
 filename.
-The
+Only the
+.Ic table-v2
+format is able to dump a multi-protocol RIB correctly.
+Both
+.Ic table
+and
 .Ic table-mp
-format is multi-protocol capable but often not supported by 3rd-party tools.
+formats are more or less limited when handling multi-protocol entries and
+are only left around to support 3rd party tools not handling the new format.
 The timeout is optional:
 .Bd -literal -offset indent
 dump table "/tmp/rib-dump-%H%M" 300
Index: mrt.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/mrt.c,v
retrieving revision 1.70
diff -u -p -r1.70 mrt.c
--- mrt.c       2 Sep 2010 14:03:21 -0000       1.70
+++ mrt.c       17 Sep 2011 12:59:46 -0000
@@ -32,10 +32,12 @@
 
 #include "mrt.h"
 
-int mrt_attr_dump(struct ibuf *, struct rde_aspath *, struct bgpd_addr *);
+int mrt_attr_dump(struct ibuf *, struct rde_aspath *, 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*);
+int mrt_dump_entry_v2(struct mrt *, struct rib_entry *, u_int32_t);
+int mrt_dump_peer(struct ibuf *, struct rde_peer *);
 int mrt_dump_hdr_se(struct ibuf **, struct peer *, u_int16_t, u_int16_t,
     u_int32_t, int);
 int mrt_dump_hdr_rde(struct ibuf **, u_int16_t type, u_int16_t, u_int32_t);
@@ -45,7 +47,7 @@ int mrt_open(struct mrt *, time_t);
        do {                                                            \
                u_char          t = (b);                                \
                if (ibuf_add((x), &t, sizeof(t)) == -1) {               \
-                       log_warnx("mrt_dump1: ibuf_add error");         \
+                       log_warn("mrt_dump1: ibuf_add error");          \
                        goto fail;                                      \
                }                                                       \
        } while (0)
@@ -55,7 +57,7 @@ int mrt_open(struct mrt *, time_t);
                u_int16_t       t;                                      \
                t = htons((s));                                         \
                if (ibuf_add((x), &t, sizeof(t)) == -1) {               \
-                       log_warnx("mrt_dump2: ibuf_add error");         \
+                       log_warn("mrt_dump2: ibuf_add error");          \
                        goto fail;                                      \
                }                                                       \
        } while (0)
@@ -65,7 +67,7 @@ int mrt_open(struct mrt *, time_t);
                u_int32_t       t;                                      \
                t = htonl((l));                                         \
                if (ibuf_add((x), &t, sizeof(t)) == -1) {               \
-                       log_warnx("mrt_dump3: ibuf_add error");         \
+                       log_warn("mrt_dump3: ibuf_add error");          \
                        goto fail;                                      \
                }                                                       \
        } while (0)
@@ -74,7 +76,7 @@ int mrt_open(struct mrt *, time_t);
        do {                                                            \
                u_int32_t       t = (l);                                \
                if (ibuf_add((x), &t, sizeof(t)) == -1) {               \
-                       log_warnx("mrt_dump4: ibuf_add error");         \
+                       log_warn("mrt_dump4: ibuf_add error");          \
                        goto fail;                                      \
                }                                                       \
        } while (0)
@@ -99,7 +101,7 @@ mrt_dump_bgp_msg(struct mrt *mrt, void *
                return;
 
        if (ibuf_add(buf, pkg, pkglen) == -1) {
-               log_warnx("mrt_dump_bgp_msg: buf_add error");
+               log_warn("mrt_dump_bgp_msg: buf_add error");
                ibuf_free(buf);
                return;
        }
@@ -132,14 +134,15 @@ fail:
 }
 
 int
-mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr 
*nexthop)
+mrt_attr_dump(struct ibuf *buf, struct rde_aspath *a, struct bgpd_addr 
*nexthop,
+    int v2)
 {
        struct attr     *oa;
        u_char          *pdata;
        u_int32_t        tmp;
        int              neednewpath = 0;
        u_int16_t        plen, afi;
-       u_int8_t         l, mpattr[21];
+       u_int8_t         l, safi;
 
        /* origin */
        if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ORIGIN,
@@ -148,7 +151,8 @@ mrt_attr_dump(struct ibuf *buf, struct r
 
        /* aspath */
        pdata = aspath_prepend(a->aspath, rde_local_as(), 0, &plen);
-       pdata = aspath_deflate(pdata, &plen, &neednewpath);
+       if (!v2)
+               pdata = aspath_deflate(pdata, &plen, &neednewpath);
        if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_ASPATH, pdata,
            plen) == -1) {
                free(pdata);
@@ -170,7 +174,7 @@ mrt_attr_dump(struct ibuf *buf, struct r
                        return (-1);
        }
 
-       /* local preference, only valid for ibgp */
+       /* local preference */
        tmp = htonl(a->lpref);
        if (attr_writebuf(buf, ATTR_WELL_KNOWN, ATTR_LOCALPREF, &tmp, 4) == -1)
                return (-1);
@@ -185,16 +189,40 @@ mrt_attr_dump(struct ibuf *buf, struct r
        }
 
        if (nexthop && nexthop->aid != AID_INET) {
-               if (aid2afi(nexthop->aid, &afi, &mpattr[2]))
+               struct ibuf *nhbuf;
+
+               if ((nhbuf = ibuf_dynamic(0, UCHAR_MAX)) == NULL)
                        return (-1);
-               afi = htons(afi);
-               memcpy(mpattr, &afi, sizeof(afi));
-               mpattr[3] = sizeof(struct in6_addr);
-               memcpy(&mpattr[4], &nexthop->v6, sizeof(struct in6_addr));
-               mpattr[20] = 0; /* Reserved must be 0 */
+               if (!v2) {
+                       if (aid2afi(nexthop->aid, &afi, &safi))
+                               return (-1);
+                       DUMP_SHORT(nhbuf, afi);
+                       DUMP_BYTE(nhbuf, safi);
+               }
+               switch (nexthop->aid) {
+               case AID_INET6:
+                       DUMP_BYTE(nhbuf, sizeof(struct in6_addr));
+                       if (ibuf_add(nhbuf, &nexthop->v6,
+                           sizeof(struct in6_addr)) == -1) {
+                       }
+                       break;
+               case AID_VPN_IPv4:
+                       DUMP_BYTE(nhbuf, sizeof(u_int64_t) +
+                           sizeof(struct in_addr));
+                       DUMP_NLONG(nhbuf, 0);   /* set RD to 0 */
+                       DUMP_NLONG(nhbuf, 0);
+                       DUMP_NLONG(nhbuf, nexthop->v4.s_addr);
+                       break;
+               }
+               if (!v2)
+                       DUMP_BYTE(nhbuf, 0);
                if (attr_writebuf(buf, ATTR_OPTIONAL, ATTR_MP_REACH_NLRI,
-                   mpattr, sizeof(mpattr)) == -1)
+                   nhbuf->buf, ibuf_size(nhbuf)) == -1) {
+fail:
+                       ibuf_free(nhbuf);
                        return (-1);
+               }
+               ibuf_free(nhbuf);
        }
 
        if (neednewpath) {
@@ -216,10 +244,8 @@ mrt_dump_entry_mp(struct mrt *mrt, struc
     struct rde_peer *peer)
 {
        struct ibuf     *buf, *hbuf = NULL, *h2buf = NULL;
-       void            *bptr;
        struct bgpd_addr addr, nexthop, *nh;
        u_int16_t        len;
-       u_int8_t         p_len;
        u_int8_t         aid;
 
        if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
@@ -227,7 +253,7 @@ mrt_dump_entry_mp(struct mrt *mrt, struc
                return (-1);
        }
 
-       if (mrt_attr_dump(buf, p->aspath, NULL) == -1) {
+       if (mrt_attr_dump(buf, p->aspath, NULL, 0) == -1) {
                log_warnx("mrt_dump_entry_mp: mrt_attr_dump error");
                goto fail;
        }
@@ -259,7 +285,7 @@ mrt_dump_entry_mp(struct mrt *mrt, struc
                    sizeof(struct in6_addr)) == -1 ||
                    ibuf_add(h2buf, &peer->remote_addr.v6,
                    sizeof(struct in6_addr)) == -1) {
-                       log_warnx("mrt_dump_entry_mp: buf_add error");
+                       log_warn("mrt_dump_entry_mp: buf_add error");
                        goto fail;
                }
                break;
@@ -292,7 +318,7 @@ mrt_dump_entry_mp(struct mrt *mrt, struc
                DUMP_BYTE(h2buf, SAFI_UNICAST); /* safi */
                DUMP_BYTE(h2buf, 16);           /* nhlen */
                if (ibuf_add(h2buf, &nh->v6, sizeof(struct in6_addr)) == -1) {
-                       log_warnx("mrt_dump_entry_mp: buf_add error");
+                       log_warn("mrt_dump_entry_mp: buf_add error");
                        goto fail;
                }
                break;
@@ -301,13 +327,8 @@ mrt_dump_entry_mp(struct mrt *mrt, struc
                goto fail;
        }
 
-       p_len = PREFIX_SIZE(p->prefix->prefixlen);
-       if ((bptr = ibuf_reserve(h2buf, p_len)) == NULL) {
-               log_warnx("mrt_dump_entry_mp: buf_reserve error");
-               goto fail;
-       }
-       if (prefix_write(bptr, p_len, &addr, p->prefix->prefixlen) == -1) {
-               log_warnx("mrt_dump_entry_mp: prefix_write error");
+       if (prefix_writebuf(h2buf, &addr, p->prefix->prefixlen) == -1) {
+               log_warn("mrt_dump_entry_mp: prefix_writebuf error");
                goto fail;
        }
 
@@ -349,7 +370,7 @@ mrt_dump_entry(struct mrt *mrt, struct p
                return (0);
 
        if ((buf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
-               log_warnx("mrt_dump_entry: buf_dynamic");
+               log_warn("mrt_dump_entry: buf_dynamic");
                return (-1);
        }
 
@@ -359,7 +380,7 @@ mrt_dump_entry(struct mrt *mrt, struct p
                nh = &addr;
        } else
                nh = &p->aspath->nexthop->exit_nexthop;
-       if (mrt_attr_dump(buf, p->aspath, nh) == -1) {
+       if (mrt_attr_dump(buf, p->aspath, nh, 0) == -1) {
                log_warnx("mrt_dump_entry: mrt_attr_dump error");
                ibuf_free(buf);
                return (-1);
@@ -381,7 +402,7 @@ mrt_dump_entry(struct mrt *mrt, struct p
                break;
        case AID_INET6:
                if (ibuf_add(hbuf, &addr.v6, sizeof(struct in6_addr)) == -1) {
-                       log_warnx("mrt_dump_entry: buf_add error");
+                       log_warn("mrt_dump_entry: buf_add error");
                        goto fail;
                }
                break;
@@ -397,7 +418,7 @@ mrt_dump_entry(struct mrt *mrt, struct p
        case AID_INET6:
                if (ibuf_add(hbuf, &peer->remote_addr.v6,
                    sizeof(struct in6_addr)) == -1) {
-                       log_warnx("mrt_dump_entry: buf_add error");
+                       log_warn("mrt_dump_entry: buf_add error");
                        goto fail;
                }
                break;
@@ -416,12 +437,214 @@ fail:
        return (-1);
 }
 
+int
+mrt_dump_entry_v2(struct mrt *mrt, struct rib_entry *re, u_int32_t snum)
+{
+       struct ibuf     *buf, *hbuf = NULL;
+       struct prefix   *p;
+       struct bgpd_addr addr;
+       size_t           len, off;
+       u_int16_t        subtype, nump;
+
+       switch (re->prefix->aid) {
+       case AID_INET:
+               subtype = MRT_DUMP_V2_RIB_IPV4_UNICAST;
+               break;
+       case AID_INET6:
+               subtype = MRT_DUMP_V2_RIB_IPV6_UNICAST;
+               break;
+       default:
+               subtype = MRT_DUMP_V2_RIB_GENERIC;
+               break;
+       }
+
+       if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
+               log_warn("mrt_dump_entry: buf_dynamic");
+               return (-1);
+       }
+
+       DUMP_LONG(buf, snum);
+       pt_getaddr(re->prefix, &addr);
+       if (subtype == MRT_DUMP_V2_RIB_GENERIC) {
+               u_int16_t afi;
+               u_int8_t safi;
+
+               aid2afi(re->prefix->aid, &afi, &safi);
+               DUMP_SHORT(buf, afi);
+               DUMP_BYTE(buf, safi);
+       }
+       if (prefix_writebuf(buf, &addr, re->prefix->prefixlen) == -1) {
+               log_warn("mrt_dump_entry_mp: prefix_writebuf error");
+               goto fail;
+       }
+
+       off = ibuf_size(buf);
+       if (ibuf_reserve(buf, sizeof(nump)) == NULL) {
+               log_warn("mrt_dump_v2_hdr: buf_reserve error");
+               goto fail;
+       }
+       nump = 0;
+       LIST_FOREACH(p, &re->prefix_h, rib_l) {
+               struct bgpd_addr        *nh;
+               struct ibuf             *tbuf;
+
+               if (p->aspath->nexthop == NULL) {
+                       bzero(&addr, sizeof(struct bgpd_addr));
+                       addr.aid = p->prefix->aid;
+                       nh = &addr;
+               } else
+                       nh = &p->aspath->nexthop->exit_nexthop;
+
+               DUMP_SHORT(buf, p->aspath->peer->mrt_idx);
+               DUMP_LONG(buf, p->lastchange); /* originated */
+
+               if ((tbuf = ibuf_dynamic(0, MAX_PKTSIZE)) == NULL) {
+                       log_warn("mrt_dump_entry_v2: buf_dynamic");
+                       return (-1);
+               }
+               if (mrt_attr_dump(tbuf, p->aspath, nh, 1) == -1) {
+                       log_warnx("mrt_dump_entry_v2: mrt_attr_dump error");
+                       ibuf_free(buf);
+                       return (-1);
+               }
+               len = ibuf_size(tbuf);
+               DUMP_SHORT(buf, (u_int16_t)len);
+               if (ibuf_add(buf, tbuf->buf, ibuf_size(tbuf)) == -1) {
+                       log_warn("mrt_dump_entry_v2: ibuf_add error");
+                       ibuf_free(tbuf);
+                       return (-1);
+               }
+               ibuf_free(tbuf);
+               nump++;
+       }
+       nump = htons(nump);
+       memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump));
+
+       len = ibuf_size(buf);
+       if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2, subtype, len) == -1) {
+               ibuf_free(buf);
+               return (-1);
+       }
+
+       ibuf_close(&mrt->wbuf, hbuf);
+       ibuf_close(&mrt->wbuf, buf);
+
+       return (0);
+fail:
+       if (hbuf)
+               ibuf_free(hbuf);
+       ibuf_free(buf);
+       return (-1);
+}
+
+int
+mrt_dump_v2_hdr(struct mrt *mrt, struct bgpd_config *conf,
+    struct rde_peer_head *ph)
+{
+       struct rde_peer *peer;
+       struct ibuf     *buf, *hbuf = NULL;
+       size_t           len, off;
+       u_int16_t        nlen, nump;
+
+       if ((buf = ibuf_dynamic(0, UINT_MAX)) == NULL) {
+               log_warn("mrt_dump_v2_hdr: buf_dynamic");
+               return (-1);
+       }
+
+       DUMP_NLONG(buf, conf->bgpid);
+       nlen = strlen(mrt->rib);
+       if (nlen > 0)
+               nlen += 1;
+       DUMP_SHORT(buf, nlen);
+       if (ibuf_add(buf, mrt->rib, nlen) == -1) {
+               log_warn("mrt_dump_v2_hdr: buf_add error");
+               goto fail;
+       }
+
+       off = ibuf_size(buf);
+       if (ibuf_reserve(buf, sizeof(nump)) == NULL) {
+               log_warn("mrt_dump_v2_hdr: buf_reserve error");
+               goto fail;
+       }
+       nump = 0;
+       LIST_FOREACH(peer, ph, peer_l) {
+               peer->mrt_idx = nump;
+               if (mrt_dump_peer(buf, peer) == -1)
+                       goto fail;
+               nump++;
+       }
+       nump = htons(nump);
+       memcpy(ibuf_seek(buf, off, sizeof(nump)), &nump, sizeof(nump));
+
+       len = ibuf_size(buf);
+       if (mrt_dump_hdr_rde(&hbuf, MSG_TABLE_DUMP_V2,
+           MRT_DUMP_V2_PEER_INDEX_TABLE, len) == -1)
+               goto fail;
+
+       ibuf_close(&mrt->wbuf, hbuf);
+       ibuf_close(&mrt->wbuf, buf);
+
+       return (0);
+fail:
+       if (hbuf)
+               ibuf_free(hbuf);
+       ibuf_free(buf);
+       return (-1);
+}
+
+int
+mrt_dump_peer(struct ibuf *buf, struct rde_peer *peer)
+{
+       u_int8_t        type = 0;
+
+       if (peer->capa.as4byte)
+               type |= MRT_DUMP_V2_PEER_BIT_A;
+       if (peer->remote_addr.aid == AID_INET6)
+               type |= MRT_DUMP_V2_PEER_BIT_I;
+
+       DUMP_BYTE(buf, type);
+       DUMP_LONG(buf, peer->remote_bgpid);
+
+       switch (peer->remote_addr.aid) {
+       case AID_INET:
+               DUMP_NLONG(buf, peer->remote_addr.v4.s_addr);
+               break;
+       case AID_INET6:
+               if (ibuf_add(buf, &peer->remote_addr.v6,
+                   sizeof(struct in6_addr)) == -1) {
+                       log_warn("mrt_dump_peer: buf_add error");
+                       goto fail;
+               }
+               break;
+       case AID_UNSPEC: /* XXX special handling for peer_self? */
+               DUMP_NLONG(buf, 0);
+               break;
+       default:
+               log_warnx("king bula found new AF in mrt_dump_entry_mp");
+               goto fail;
+       }
+
+       if (peer->capa.as4byte)
+               DUMP_LONG(buf, peer->conf.remote_as);
+       else
+               DUMP_SHORT(buf, peer->short_as);
+
+       return (0);
+fail:
+       return (-1);
+}
+
 void
 mrt_dump_upcall(struct rib_entry *re, void *ptr)
 {
        struct mrt              *mrtbuf = ptr;
        struct prefix           *p;
 
+       if (mrtbuf->type == MRT_TABLE_DUMP_V2) {
+               mrt_dump_entry_v2(mrtbuf, re, mrtbuf->seqnum++);
+               return;
+       }
+
        /*
         * dump all prefixes even the inactive ones. That is the way zebra
         * dumps the table so we do the same. If only the active route should
@@ -453,7 +676,7 @@ mrt_dump_hdr_se(struct ibuf ** bp, struc
 
        if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
            MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + len)) == NULL) {
-               log_warnx("mrt_dump_hdr_se: buf_open error");
+               log_warn("mrt_dump_hdr_se: buf_open error");
                return (-1);
        }
 
@@ -522,20 +745,20 @@ mrt_dump_hdr_se(struct ibuf ** bp, struc
                        if (ibuf_add(*bp, &((struct sockaddr_in6 *)
                            &peer->sa_local)->sin6_addr,
                            sizeof(struct in6_addr)) == -1) {
-                               log_warnx("mrt_dump_hdr_se: buf_add error");
+                               log_warn("mrt_dump_hdr_se: buf_add error");
                                goto fail;
                        }
                if (ibuf_add(*bp,
                    &((struct sockaddr_in6 *)&peer->sa_remote)->sin6_addr,
                    sizeof(struct in6_addr)) == -1) {
-                       log_warnx("mrt_dump_hdr_se: buf_add error");
+                       log_warn("mrt_dump_hdr_se: buf_add error");
                        goto fail;
                }
                if (swap)
                        if (ibuf_add(*bp, &((struct sockaddr_in6 *)
                            &peer->sa_local)->sin6_addr,
                            sizeof(struct in6_addr)) == -1) {
-                               log_warnx("mrt_dump_hdr_se: buf_add error");
+                               log_warn("mrt_dump_hdr_se: buf_add error");
                                goto fail;
                        }
                break;
@@ -557,7 +780,7 @@ mrt_dump_hdr_rde(struct ibuf **bp, u_int
        if ((*bp = ibuf_dynamic(MRT_HEADER_SIZE, MRT_HEADER_SIZE +
            MRT_BGP4MP_AS4_IPv6_HEADER_SIZE + MRT_BGP4MP_IPv6_ENTRY_SIZE)) ==
            NULL) {
-               log_warnx("mrt_dump_hdr_rde: buf_dynamic error");
+               log_warn("mrt_dump_hdr_rde: buf_dynamic error");
                return (-1);
        }
 
@@ -579,6 +802,7 @@ mrt_dump_hdr_rde(struct ibuf **bp, u_int
                DUMP_LONG(*bp, len);
                break;
        case MSG_PROTOCOL_BGP4MP:
+       case MSG_TABLE_DUMP_V2:
                DUMP_LONG(*bp, len);
                break;
        default:
@@ -650,7 +874,8 @@ mrt_open(struct mrt *mrt, time_t now)
        else
                type = IMSG_MRT_REOPEN;
 
-       if (mrt->type == MRT_TABLE_DUMP || mrt->type == MRT_TABLE_DUMP_MP)
+       if (mrt->type == MRT_TABLE_DUMP || mrt->type == MRT_TABLE_DUMP_MP ||
+           mrt->type == MRT_TABLE_DUMP_V2)
                i = 0;
 
        if (imsg_compose(mrt_imsgbuf[i], type, 0, 0, fd,
@@ -719,7 +944,9 @@ mrt_handler(struct mrt_head *mrt)
        LIST_FOREACH(m, mrt, entry) {
                if (m->state == MRT_STATE_RUNNING &&
                    (MRT2MC(m)->ReopenTimerInterval != 0 ||
-                    m->type == MRT_TABLE_DUMP)) {
+                    m->type == MRT_TABLE_DUMP ||
+                    m->type == MRT_TABLE_DUMP_MP ||
+                    m->type == MRT_TABLE_DUMP_V2)) {
                        if (mrt_open(m, now) == -1)
                                continue;
                        MRT2MC(m)->ReopenTimer =
Index: mrt.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/mrt.h,v
retrieving revision 1.28
diff -u -p -r1.28 mrt.h
--- mrt.h       16 Sep 2011 15:44:42 -0000      1.28
+++ mrt.h       17 Sep 2011 08:58:15 -0000
@@ -104,6 +104,7 @@ enum MRT_BGP4MP_TYPES {
  *
  * The source_ip and dest_ip are dependant of the afi type. For IPv6 source_ip
  * and dest_ip are both 16 bytes long.
+ * For the AS4 types the source_as and dest_as numbers are both 4 bytes long.
  *
  * Payload of a BGP4MP_STATE_CHANGE packet:
  *
@@ -155,6 +156,98 @@ enum MRT_BGP4MP_TYPES {
  */
 
 /*
+ * New MRT dump format MSG_TABLE_DUMP_V2, the dump is implemented with
+ * sub-tables for peers and NLRI entries just use the index into the peer
+ * table.
+ */
+enum MRT_DUMP_V2_TYPES {
+       MRT_DUMP_V2_PEER_INDEX_TABLE=1,
+       MRT_DUMP_V2_RIB_IPV4_UNICAST=2,
+       MRT_DUMP_V2_RIB_IPV4_MULTICAST=3,
+       MRT_DUMP_V2_RIB_IPV6_UNICAST=4,
+       MRT_DUMP_V2_RIB_IPV6_MULTICAST=5,
+       MRT_DUMP_V2_RIB_GENERIC=6
+};
+
+/*
+ * Format of the MRT_DUMP_V2_PEER_INDEX_TABLE:
+ * If there is no view_name, view_name_len must be set to 0
+ *
+ * +--------+--------+--------+--------+
+ * |         collector_bgp_id          |
+ * +--------+--------+--------+--------+
+ * |  view_name_len  |    view_name
+ * +--------+--------+--------+--------+
+ *        view_name (variable) ...     |
+ * +--------+--------+--------+--------+
+ * |   peer_count    |   peer_entries
+ * +--------+--------+--------+--------+
+ *       peer_entries (variable) ...
+ * +--------+--------+--------+--------+
+ *
+ * The format of a peer_entry is the following:
+ *
+ * +--------+
+ * |  type  |    
+ * +--------+--------+--------+--------+
+ * |            peer_bgp_id            |
+ * +--------+--------+--------+--------+
+ * |       peer_ip_addr (variable)     |
+ * +--------+--------+--------+--------+
+ * |            peer_as (variable)     |
+ * +--------+--------+--------+--------+
+ *
+ * The message is packed a bit strangely. The type byte defines what size
+ * the peer addr and peer AS have.
+ * The position of a peer in the PEER_INDEX_TABLE is used as the index for
+ * the other messages.
+ */
+#define MRT_DUMP_V2_PEER_BIT_I 0x1     /* set for IPv6 addrs */
+#define MRT_DUMP_V2_PEER_BIT_A 0x2     /* set for 32 bits AS number */
+
+/*
+ * AFI/SAFI specific RIB Subtypes are special to save a few bytes.
+ * 
+ * +--------+--------+--------+--------+
+ * |              seq_num              |
+ * +--------+--------+--------+--------+
+ * |  plen  |  prefix (variable)
+ * +--------+--------+--------+--------+
+ * | #entry |  rib entries (variable)
+ * +--------+--------+--------+--------+
+ *
+ * The RIB_GENERIC subtype is needed for the less common AFI/SAFI pairs
+ *
+ * +--------+--------+--------+--------+
+ * |              seq_num              |
+ * +--------+--------+--------+--------+
+ * |       AFI       |  SAFI  |  NLRI
+ * +--------+--------+--------+--------+
+ *     NLRI (variable) ...
+ * +--------+--------+--------+--------+
+ * | #entry |  rib entries (variable)
+ * +--------+--------+--------+--------+
+ */
+
+/*
+ * The RIB entries have the following form.
+ *
+ * +--------+--------+
+ * |   peer index    |
+ * +--------+--------+--------+--------+
+ * |          originated_time          |
+ * +--------+--------+--------+--------+
+ * |    attr_len     |   bgp_attrs
+ * +--------+--------+--------+--------+
+ *      bgp_attrs (variable) ...
+ * +--------+--------+--------+--------+
+ *
+ * Some BGP path attributes need special encoding:
+ *  - the AS_PATH attribute MUST be encoded as 4-Byte AS
+ *  - the MP_REACH_NLRI only consists of the nexthop len and nexthop address
+ */
+
+/*
  * Format for routing table dumps in "old" mrt format.
  * Type MSG_TABLE_DUMP and subtype is AFI_IPv4 (1) for IPv4 and AFI_IPv6 (2)
  * for IPv6. In the IPv6 case prefix and peer_ip are both 16 bytes long.
@@ -171,7 +264,7 @@ enum MRT_BGP4MP_TYPES {
  *       peer_ip     |     peer_as     |
  * +--------+--------+--------+--------+
  * |    attr_len     | bgp attributes
- * +--------+--------+--------+--------+
+ 
  *  bgp attributes, attr_len bytes long
  * +--------+--------+--------+--------+
  *   ...                      |
@@ -225,7 +318,7 @@ enum MRT_BGP_TYPES {
  */
 
 /*
- * For subtype MSG_BGP_STATECHANGE (for all BGP types or just for the
+ * For subtype MSG_BGP_STATE_CHANGE (for all BGP types or just for the
  * MSG_PROTOCOL_BGP4PLUS case? Unclear.)
  *
  * +--------+--------+--------+--------+
@@ -236,7 +329,7 @@ enum MRT_BGP_TYPES {
  * |    new_state    |
  * +--------+--------+
  *
- * State are defined in RFC 1771/4271.
+ * States are defined in RFC 1771/4271.
  */
 
 /*
@@ -258,6 +351,7 @@ enum mrt_type {
        MRT_NONE,
        MRT_TABLE_DUMP,
        MRT_TABLE_DUMP_MP,
+       MRT_TABLE_DUMP_V2,
        MRT_ALL_IN,
        MRT_ALL_OUT,
        MRT_UPDATE_IN,
@@ -293,6 +387,8 @@ struct mrt_config {
 #define        MRT2MC(x)       ((struct mrt_config *)(x))
 #define        MRT_MAX_TIMEOUT 7200
 
+struct bgpd_config;
+struct rde_peer_head;
 struct peer;
 struct prefix;
 struct rib_entry;
@@ -302,6 +398,8 @@ void                 mrt_dump_bgp_msg(struct mrt *, vo
                     struct peer *);
 void            mrt_dump_state(struct mrt *, u_int16_t, u_int16_t,
                     struct peer *);
+int             mrt_dump_v2_hdr(struct mrt *, struct bgpd_config *,
+                   struct rde_peer_head *);
 void            mrt_clear_seq(void);
 void            mrt_dump_upcall(struct rib_entry *, void *);
 void            mrt_done(void *);
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.259
diff -u -p -r1.259 parse.y
--- parse.y     1 May 2011 12:56:04 -0000       1.259
+++ parse.y     16 Sep 2011 17:00:19 -0000
@@ -449,6 +449,8 @@ conf_main   : AS as4number          {
                                action = MRT_TABLE_DUMP;
                        else if (!strcmp($2, "table-mp"))
                                action = MRT_TABLE_DUMP_MP;
+                       else if (!strcmp($2, "table-v2"))
+                               action = MRT_TABLE_DUMP_V2;
                        else {
                                yyerror("unknown mrt dump type");
                                free($2);
@@ -476,6 +478,8 @@ conf_main   : AS as4number          {
                                action = MRT_TABLE_DUMP;
                        else if (!strcmp($4, "table-mp"))
                                action = MRT_TABLE_DUMP_MP;
+                       else if (!strcmp($4, "table-v2"))
+                               action = MRT_TABLE_DUMP_V2;
                        else {
                                yyerror("unknown mrt dump type");
                                free($3);
Index: printconf.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/printconf.c,v
retrieving revision 1.85
diff -u -p -r1.85 printconf.c
--- printconf.c 31 Dec 2010 21:22:42 -0000      1.85
+++ printconf.c 17 Sep 2011 15:47:59 -0000
@@ -604,6 +604,8 @@ mrt_type(enum mrt_type t)
                return "table";
        case MRT_TABLE_DUMP_MP:
                return "table-mp";
+       case MRT_TABLE_DUMP_V2:
+               return "table-v2";
        case MRT_ALL_IN:
                return "all in";
        case MRT_ALL_OUT:
@@ -632,13 +634,12 @@ print_mrt(u_int32_t pid, u_int32_t gid, 
                        printf("%s%sdump ", prep, prep2);
                        if (m->rib[0])
                                printf("rib %s ", m->rib);
+                       printf("%s \"%s\"", mrt_type(m->type),
+                           MRT2MC(m)->name);
                        if (MRT2MC(m)->ReopenTimerInterval == 0)
-                               printf("%s %s\n", mrt_type(m->type),
-                                   MRT2MC(m)->name);
+                               printf("\n");
                        else
-                               printf("%s %s %d\n", mrt_type(m->type),
-                                   MRT2MC(m)->name,
-                                   MRT2MC(m)->ReopenTimerInterval);
+                               printf(" %d\n", MRT2MC(m)->ReopenTimerInterval);
                }
 }
 
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.308
diff -u -p -r1.308 rde.c
--- rde.c       9 Jul 2011 02:51:18 -0000       1.308
+++ rde.c       17 Sep 2011 10:44:00 -0000
@@ -820,7 +820,8 @@ rde_dispatch_imsg_parent(struct imsgbuf 
                                log_warnx("expected to receive fd for mrt dump "
                                    "but didn't receive any");
                        else if (xmrt.type == MRT_TABLE_DUMP ||
-                           xmrt.type == MRT_TABLE_DUMP_MP) {
+                           xmrt.type == MRT_TABLE_DUMP_MP ||
+                           xmrt.type == MRT_TABLE_DUMP_V2) {
                                rde_dump_mrt_new(&xmrt, imsg.hdr.pid, fd);
                        } else
                                close(fd);
@@ -2336,6 +2337,10 @@ rde_dump_mrt_new(struct mrt *mrt, pid_t 
                free(ctx);
                return;
        }
+
+       if (ctx->mrt.type == MRT_TABLE_DUMP_V2)
+               mrt_dump_v2_hdr(&ctx->mrt, conf, &peerlist);
+
        ctx->ribctx.ctx_count = RDE_RUNNER_ROUNDS;
        ctx->ribctx.ctx_rib = &ribs[id];
        ctx->ribctx.ctx_upcall = mrt_dump_upcall;
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.138
diff -u -p -r1.138 rde.h
--- rde.h       18 Nov 2010 12:18:31 -0000      1.138
+++ rde.h       17 Sep 2011 12:58:14 -0000
@@ -72,6 +72,7 @@ struct rde_peer {
        enum peer_state                  state;
        u_int16_t                        ribid;
        u_int16_t                        short_as;
+       u_int16_t                        mrt_idx;
        u_int8_t                         reconf_in;     /* in filter changed */
        u_int8_t                         reconf_out;    /* out filter changed */
        u_int8_t                         reconf_rib;    /* rib changed */
@@ -401,6 +402,7 @@ void                 prefix_move(struct rde_aspath *, 
 int             prefix_remove(struct rib *, struct rde_peer *,
                    struct bgpd_addr *, int, u_int32_t);
 int             prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t);
+int             prefix_writebuf(struct ibuf *, struct bgpd_addr *, u_int8_t);
 struct prefix  *prefix_bypeer(struct rib_entry *, struct rde_peer *,
                     u_int32_t);
 void            prefix_updateall(struct rde_aspath *, enum nexthop_state,
Index: rde_rib.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_rib.c,v
retrieving revision 1.128
diff -u -p -r1.128 rde_rib.c
--- rde_rib.c   14 Jan 2011 20:07:00 -0000      1.128
+++ rde_rib.c   17 Sep 2011 11:42:56 -0000
@@ -856,6 +856,31 @@ prefix_write(u_char *buf, int len, struc
        }
 }
 
+int
+prefix_writebuf(struct ibuf *buf, struct bgpd_addr *prefix, u_int8_t plen)
+{
+       int      totlen;
+       void    *bptr;
+
+       switch (prefix->aid) {
+       case AID_INET:
+       case AID_INET6:
+               totlen = PREFIX_SIZE(plen);
+               break;
+       case AID_VPN_IPv4:
+               totlen = PREFIX_SIZE(plen) + sizeof(prefix->vpn4.rd) +
+                   prefix->vpn4.labellen;
+       default:
+               return (-1);
+       }
+
+       if ((bptr = ibuf_reserve(buf, totlen)) == NULL)
+               return (-1);
+       if (prefix_write(bptr, totlen, prefix, plen) == -1)
+               return (-1);
+       return (0);
+}
+
 /*
  * Searches in the prefix list of specified pt_entry for a prefix entry
  * belonging to the peer peer. Returns NULL if no match found.

Reply via email to