diff options
-rw-r--r-- | usr.sbin/bgpd/bgpd.8 | 13 | ||||
-rw-r--r-- | usr.sbin/bgpd/bgpd.conf.5 | 18 | ||||
-rw-r--r-- | usr.sbin/bgpd/mrt.c | 309 | ||||
-rw-r--r-- | usr.sbin/bgpd/mrt.h | 106 | ||||
-rw-r--r-- | usr.sbin/bgpd/parse.y | 6 | ||||
-rw-r--r-- | usr.sbin/bgpd/printconf.c | 13 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.c | 9 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde.h | 4 | ||||
-rw-r--r-- | usr.sbin/bgpd/rde_rib.c | 27 |
9 files changed, 438 insertions, 67 deletions
diff --git a/usr.sbin/bgpd/bgpd.8 b/usr.sbin/bgpd/bgpd.8 index c74b7268ba5..b5d41f282c6 100644 --- a/usr.sbin/bgpd/bgpd.8 +++ b/usr.sbin/bgpd/bgpd.8 @@ -1,4 +1,4 @@ -.\" $OpenBSD: bgpd.8,v 1.39 2010/10/15 07:45:32 claudio Exp $ +.\" $OpenBSD: bgpd.8,v 1.40 2011/09/17 16:29:44 claudio Exp $ .\" .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: October 15 2010 $ +.Dd $Mdocdate: September 17 2011 $ .Dt BGPD 8 .Os .Sh NAME @@ -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 diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5 index 5b8be1627cd..c3454ccd18c 100644 --- a/usr.sbin/bgpd/bgpd.conf.5 +++ b/usr.sbin/bgpd/bgpd.conf.5 @@ -1,4 +1,4 @@ -.\" $OpenBSD: bgpd.conf.5,v 1.115 2011/06/23 20:35:22 sthen Exp $ +.\" $OpenBSD: bgpd.conf.5,v 1.116 2011/09/17 16:29:44 claudio Exp $ .\" .\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> .\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -16,7 +16,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: June 23 2011 $ +.Dd $Mdocdate: September 17 2011 $ .Dt BGPD.CONF 5 .Os .Sh NAME @@ -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 diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c index d2bfe6475d8..d83325252ff 100644 --- a/usr.sbin/bgpd/mrt.c +++ b/usr.sbin/bgpd/mrt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.c,v 1.70 2010/09/02 14:03:21 sobrado Exp $ */ +/* $OpenBSD: mrt.c,v 1.71 2011/09/17 16:29:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -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 *pkg, u_int16_t pkglen, 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 rde_aspath *a, struct bgpd_addr *nexthop) /* 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 rde_aspath *a, struct bgpd_addr *nexthop) 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 rde_aspath *a, struct bgpd_addr *nexthop) } 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, struct prefix *p, u_int16_t snum, 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, struct prefix *p, u_int16_t snum, 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, struct prefix *p, u_int16_t snum, 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, struct prefix *p, u_int16_t snum, 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, struct prefix *p, u_int16_t snum, 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 prefix *p, u_int16_t snum, 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 prefix *p, u_int16_t snum, 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 prefix *p, u_int16_t snum, 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 prefix *p, u_int16_t snum, 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, struct peer *peer, u_int16_t type, 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, struct peer *peer, u_int16_t type, 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_int16_t type, u_int16_t subtype, 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_int16_t type, u_int16_t subtype, 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 = diff --git a/usr.sbin/bgpd/mrt.h b/usr.sbin/bgpd/mrt.h index bb9af163b80..352b65c2ad2 100644 --- a/usr.sbin/bgpd/mrt.h +++ b/usr.sbin/bgpd/mrt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.h,v 1.28 2011/09/16 15:44:42 claudio Exp $ */ +/* $OpenBSD: mrt.h,v 1.29 2011/09/17 16:29:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -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 *, void *, u_int16_t, 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 *); diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index 75798d892f4..6939faaaee6 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.259 2011/05/01 12:56:04 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.260 2011/09/17 16:29:44 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -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); diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index 76d260b548d..6599761c638 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.85 2010/12/31 21:22:42 guenther Exp $ */ +/* $OpenBSD: printconf.c,v 1.86 2011/09/17 16:29:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -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, const char *prep, const char *prep2) 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); } } diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c index 288a7913a67..5efa9bef765 100644 --- a/usr.sbin/bgpd/rde.c +++ b/usr.sbin/bgpd/rde.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.c,v 1.308 2011/07/09 02:51:18 henning Exp $ */ +/* $OpenBSD: rde.c,v 1.309 2011/09/17 16:29:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> @@ -820,7 +820,8 @@ rde_dispatch_imsg_parent(struct imsgbuf *ibuf) 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 pid, int fd) 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; diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h index d2a594b9696..853fbfb6f23 100644 --- a/usr.sbin/bgpd/rde.h +++ b/usr.sbin/bgpd/rde.h @@ -1,4 +1,4 @@ -/* $OpenBSD: rde.h,v 1.138 2010/11/18 12:18:31 claudio Exp $ */ +/* $OpenBSD: rde.h,v 1.139 2011/09/17 16:29:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and @@ -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 *, struct prefix *); 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, diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c index fcbfac9e218..a7297ca6004 100644 --- a/usr.sbin/bgpd/rde_rib.c +++ b/usr.sbin/bgpd/rde_rib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rde_rib.c,v 1.128 2011/01/14 20:07:00 henning Exp $ */ +/* $OpenBSD: rde_rib.c,v 1.129 2011/09/17 16:29:44 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -856,6 +856,31 @@ prefix_write(u_char *buf, int len, struct bgpd_addr *prefix, u_int8_t plen) } } +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. |