diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-08-13 14:03:21 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2004-08-13 14:03:21 +0000 |
commit | e3c8d54a792ae8babd51739f377ebc34a8498a35 (patch) | |
tree | af3a5f9f65e445023839ef552bdf3d593494426d /usr.sbin/bgpd/mrt.c | |
parent | d292483c42a9ff83da5520765dc5ef88c785dba1 (diff) |
Fix minor issues with IPv6 dumps and add a function for dumping the RIB table
protocol independent. This new dump format is not (yet) supported by the
mrtd route_btoa tool. OK henning@
Diffstat (limited to 'usr.sbin/bgpd/mrt.c')
-rw-r--r-- | usr.sbin/bgpd/mrt.c | 200 |
1 files changed, 181 insertions, 19 deletions
diff --git a/usr.sbin/bgpd/mrt.c b/usr.sbin/bgpd/mrt.c index 17347d1e5df..f214782554e 100644 --- a/usr.sbin/bgpd/mrt.c +++ b/usr.sbin/bgpd/mrt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mrt.c,v 1.43 2004/08/11 16:48:45 claudio Exp $ */ +/* $OpenBSD: mrt.c,v 1.44 2004/08/13 14:03:20 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> @@ -32,11 +32,13 @@ #include "mrt.h" -static u_int16_t mrt_attr_length(struct rde_aspath *); +static u_int16_t mrt_attr_length(struct rde_aspath *, int); static int mrt_attr_dump(void *, u_int16_t, struct rde_aspath *, struct bgpd_addr *); +static int mrt_dump_entry_mp(struct mrt *, struct prefix *, + u_int16_t, struct rde_peer*); static int mrt_dump_entry(struct mrt *, struct prefix *, - u_int16_t, struct peer_config *); + u_int16_t, struct rde_peer*); static int mrt_dump_header(struct buf *, u_int16_t, u_int16_t, u_int32_t); static int mrt_open(struct mrt *, time_t); @@ -90,7 +92,16 @@ mrt_dump_bgp_msg(struct mrt *mrt, void *pkg, u_int16_t pkglen, struct buf *buf; u_int16_t len; - len = pkglen + MRT_BGP4MP_HEADER_SIZE; + switch (peer->sa_local.ss_family) { + case AF_INET: + len = pkglen + MRT_BGP4MP_IPv4_HEADER_SIZE; + break; + case AF_INET6: + len = pkglen + MRT_BGP4MP_IPv6_HEADER_SIZE; + break; + default: + return (-1); + } if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { log_warnx("mrt_dump_bgp_msg: buf_open error"); @@ -148,7 +159,16 @@ mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state, struct buf *buf; u_int16_t len; - len = 4 + MRT_BGP4MP_HEADER_SIZE; + switch (peer->sa_local.ss_family) { + case AF_INET: + len = 4 + MRT_BGP4MP_IPv4_HEADER_SIZE; + break; + case AF_INET6: + len = 4 + MRT_BGP4MP_IPv6_HEADER_SIZE; + break; + default: + return (-1); + } if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { log_warnx("mrt_dump_bgp_state: buf_open error"); @@ -197,12 +217,14 @@ mrt_dump_state(struct mrt *mrt, u_int16_t old_state, u_int16_t new_state, } static u_int16_t -mrt_attr_length(struct rde_aspath *a) +mrt_attr_length(struct rde_aspath *a, int oldform) { struct attr *oa; u_int16_t alen, plen; - alen = 4 /* origin */ + 7 /* nexthop */ + 7 /* lpref */; + alen = 4 /* origin */ + 7 /* lpref */; + if (oldform) + alen += 7 /* nexthop */; plen = aspath_length(a->aspath); alen += 2 + plen + (plen > 255 ? 2 : 1); if (a->med != 0) @@ -237,11 +259,13 @@ mrt_attr_dump(void *p, u_int16_t len, struct rde_aspath *a, return (-1); wlen += r; len -= r; - /* nexthop, already network byte order */ - if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, ATTR_NEXTHOP, - &nexthop->v4.s_addr, 4)) == -1) - return (-1); - wlen += r; len -= r; + if (nexthop) { + /* nexthop, already network byte order */ + if ((r = attr_write(buf + wlen, len, ATTR_WELL_KNOWN, + ATTR_NEXTHOP, &nexthop->v4.s_addr, 4)) == -1) + return (-1); + wlen += r; len -= r; + } /* MED, non transitive */ if (a->med != 0) { @@ -271,15 +295,151 @@ mrt_attr_dump(void *p, u_int16_t len, struct rde_aspath *a, } static int +mrt_dump_entry_mp(struct mrt *mrt, struct prefix *p, u_int16_t snum, + struct rde_peer *peer) +{ + struct buf *buf; + void *bptr; + struct bgpd_addr addr, nexthop, *nh; + u_int16_t len, attr_len; + u_int8_t p_len; + sa_family_t af; + + attr_len = mrt_attr_length(p->aspath, 0); + p_len = PREFIX_SIZE(p->prefix->prefixlen); + pt_getaddr(p->prefix, &addr); + + af = peer->remote_addr.af == 0 ? addr.af : peer->remote_addr.af; + switch (af) { + case AF_INET: + len = MRT_BGP4MP_IPv4_HEADER_SIZE; + break; + case AF_INET6: + len = MRT_BGP4MP_IPv6_HEADER_SIZE; + break; + default: + return (-1); + } + + switch (addr.af) { + case AF_INET: + len += MRT_BGP4MP_IPv4_ENTRY_SIZE + p_len + attr_len; + break; + case AF_INET6: + len += MRT_BGP4MP_IPv4_ENTRY_SIZE + p_len + attr_len; + break; + default: + return (-1); + } + + if ((buf = buf_open(len + MRT_HEADER_SIZE)) == NULL) { + log_warnx("mrt_dump_entry_mp: buf_open error"); + return (-1); + } + + if (mrt_dump_header(buf, MSG_PROTOCOL_BGP4MP, BGP4MP_ENTRY, + len) == -1) { + log_warnx("mrt_dump_entry_mp: buf_add error"); + return (-1); + } + + DUMP_SHORT(buf, rde_local_as()); + DUMP_SHORT(buf, peer->conf.remote_as); + DUMP_SHORT(buf, /* ifindex */ 0); + + switch (af) { + case AF_INET: + DUMP_SHORT(buf, AFI_IPv4); + DUMP_NLONG(buf, peer->local_addr.v4.s_addr); + DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); + break; + case AF_INET6: + DUMP_SHORT(buf, AFI_IPv6); + if (buf_add(buf, &peer->local_addr.v6, + sizeof(struct in6_addr)) == -1 || + buf_add(buf, &peer->remote_addr.v6, + sizeof(struct in6_addr)) == -1) { + log_warnx("mrt_dump_entry_mp: buf_add error"); + buf_free(buf); + return (-1); + } + break; + } + + DUMP_SHORT(buf, 0); /* view */ + DUMP_SHORT(buf, 1); /* status */ + DUMP_LONG(buf, p->lastchange); /* originated */ + + if (p->aspath->nexthop == NULL) { + bzero(&nexthop, sizeof(struct bgpd_addr)); + nexthop.af = addr.af; + nh = &nexthop; + } else + nh = &p->aspath->nexthop->exit_nexthop; + + switch (addr.af) { + case AF_INET: + DUMP_SHORT(buf, AFI_IPv4); /* afi */ + DUMP_BYTE(buf, SAFI_UNICAST); /* safi */ + DUMP_BYTE(buf, 4); /* nhlen */ + DUMP_NLONG(buf, nh->v4.s_addr); /* nexthop */ + break; + case AF_INET6: + DUMP_SHORT(buf, AFI_IPv6); /* afi */ + DUMP_BYTE(buf, SAFI_UNICAST); /* safi */ + DUMP_BYTE(buf, 16); /* nhlen */ + if (buf_add(buf, &nh->v6, sizeof(struct in6_addr)) == -1) { + log_warnx("mrt_dump_entry_mp: buf_add error"); + buf_free(buf); + return (-1); + } + break; + } + + if ((bptr = buf_reserve(buf, p_len)) == NULL) { + log_warnx("mrt_dump_entry_mpbuf_reserve error"); + buf_free(buf); + return (-1); + } + if (prefix_write(bptr, p_len, &addr, p->prefix->prefixlen) == -1) { + log_warnx("mrt_dump_entry_mpprefix_write error"); + buf_free(buf); + return (-1); + } + + DUMP_SHORT(buf, attr_len); + if ((bptr = buf_reserve(buf, attr_len)) == NULL) { + log_warnx("mrt_dump_entry_mpbuf_reserve error"); + buf_free(buf); + return (-1); + } + + if (mrt_attr_dump(bptr, attr_len, p->aspath, NULL) == -1) { + log_warnx("mrt_dump_entry_mpmrt_attr_dump error"); + buf_free(buf); + return (-1); + } + + TAILQ_INSERT_TAIL(&mrt->bufs, buf, entry); + mrt->queued++; + + return (len + MRT_HEADER_SIZE); +} + +static int mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, - struct peer_config *peer) + struct rde_peer *peer) { struct buf *buf; void *bptr; struct bgpd_addr addr, *nh; u_int16_t len, attr_len; - attr_len = mrt_attr_length(p->aspath); + if (p->prefix->af != AF_INET && peer->remote_addr.af == AF_INET) + /* only for true IPv4 */ + return (0); + + attr_len = mrt_attr_length(p->aspath, 1); len = MRT_DUMP_HEADER_SIZE + attr_len; pt_getaddr(p->prefix, &addr); @@ -289,7 +449,7 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, } if (mrt_dump_header(buf, MSG_TABLE_DUMP, AFI_IPv4, len) == -1) { - log_warnx("mrt_dump_bgp_msg: buf_add error"); + log_warnx("mrt_dump_entry: buf_add error"); return (-1); } @@ -300,9 +460,9 @@ mrt_dump_entry(struct mrt *mrt, struct prefix *p, u_int16_t snum, DUMP_BYTE(buf, 1); /* state */ DUMP_LONG(buf, p->lastchange); /* originated */ DUMP_NLONG(buf, peer->remote_addr.v4.s_addr); - DUMP_SHORT(buf, peer->remote_as); - DUMP_SHORT(buf, attr_len); + DUMP_SHORT(buf, peer->conf.remote_as); + DUMP_SHORT(buf, attr_len); if ((bptr = buf_reserve(buf, attr_len)) == NULL) { log_warnx("mrt_dump_entry: buf_reserve error"); buf_free(buf); @@ -347,8 +507,10 @@ mrt_dump_upcall(struct pt_entry *pt, void *ptr) * be dumped p should be set to p = pt->active. */ LIST_FOREACH(p, &pt->prefix_h, prefix_l) - mrt_dump_entry(mrtbuf, p, sequencenum++, - &p->peer->conf); + if (mrtbuf->type == MRT_TABLE_DUMP) + mrt_dump_entry(mrtbuf, p, sequencenum++, p->peer); + else + mrt_dump_entry_mp(mrtbuf, p, sequencenum++, p->peer); } static int |