diff options
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r-- | proto/bgp/packets.c | 105 |
1 files changed, 93 insertions, 12 deletions
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 91b47927..03cc4ee0 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -13,6 +13,7 @@ #include "nest/protocol.h" #include "nest/route.h" #include "nest/attrs.h" +#include "nest/mrtdump.h" #include "conf/conf.h" #include "lib/unaligned.h" #include "lib/socket.h" @@ -23,6 +24,84 @@ static struct rate_limit rl_rcv_update, rl_snd_update; +/* + * MRT Dump format is not semantically specified. + * We will use these values in appropriate fields: + * + * Local AS, Remote AS - configured AS numbers for given BGP instance. + * Local IP, Remote IP - IP addresses of the TCP connection (0 if no connection) + * + * We dump two kinds of MRT messages: STATE_CHANGE (for BGP state + * changes) and MESSAGE (for received BGP messages). + * + * STATE_CHANGE uses always AS4 variant, but MESSAGE uses AS4 variant + * only when AS4 session is established and even in that case MESSAGE + * does not use AS4 variant for initial OPEN message. This strange + * behavior is here for compatibility with Quagga and Bgpdump, + */ + +static byte * +mrt_put_bgp4_hdr(byte *buf, struct bgp_conn *conn, int as4) +{ + struct bgp_proto *p = conn->bgp; + ip_addr local_addr; + + if (as4) + { + put_u32(buf+0, p->remote_as); + put_u32(buf+4, p->local_as); + buf+=8; + } + else + { + put_u16(buf+0, (p->remote_as <= 0xFFFF) ? p->remote_as : AS_TRANS); + put_u16(buf+2, (p->local_as <= 0xFFFF) ? p->local_as : AS_TRANS); + buf+=4; + } + + put_u16(buf+0, p->neigh->iface->index); + put_u16(buf+2, BGP_AF); + buf+=4; + buf = ipa_put_addr(buf, conn->sk ? conn->sk->daddr : IPA_NONE); + buf = ipa_put_addr(buf, conn->sk ? conn->sk->saddr : IPA_NONE); + + return buf; +} + +static void +mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, unsigned len) +{ + byte buf[BGP_MAX_PACKET_LENGTH + 128]; + byte *bp = buf + MRTDUMP_HDR_LENGTH; + int as4 = conn->bgp->as4_session; + + bp = mrt_put_bgp4_hdr(bp, conn, as4); + memcpy(bp, pkt, len); + bp += len; + mrt_dump_message(&conn->bgp->p, BGP4MP, as4 ? BGP4MP_MESSAGE_AS4 : BGP4MP_MESSAGE, + buf, bp-buf); +} + +static inline u16 +convert_state(unsigned state) +{ + /* Convert state from our BS_* values to values used in MRTDump */ + return (state == BS_CLOSE) ? 1 : state + 1; +} + +void +mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new) +{ + byte buf[128]; + byte *bp = buf + MRTDUMP_HDR_LENGTH; + + bp = mrt_put_bgp4_hdr(bp, conn, 1); + put_u16(bp+0, convert_state(old)); + put_u16(bp+2, convert_state(new)); + bp += 4; + mrt_dump_message(&conn->bgp->p, BGP4MP, BGP4MP_STATE_CHANGE_AS4, buf, bp-buf); +} + static byte * bgp_create_notification(struct bgp_conn *conn, byte *buf) { @@ -403,13 +482,8 @@ bgp_create_route_refresh(struct bgp_conn *conn, byte *buf) struct bgp_proto *p = conn->bgp; BGP_TRACE(D_PACKETS, "Sending ROUTE-REFRESH"); -#ifdef IPV6 - *buf++ = 0; /* AFI IPv6 */ - *buf++ = BGP_AF_IPV6; -#else - *buf++ = 0; /* AFI IPv4 */ - *buf++ = BGP_AF_IPV4; -#endif + *buf++ = 0; + *buf++ = BGP_AF; *buf++ = 0; /* RFU */ *buf++ = 1; /* and SAFI 1 */ return buf; @@ -552,12 +626,13 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len) switch (opt[0]) { - case 2: + case 2: /* Route refresh capability, RFC 2918 */ if (cl != 0) goto err; conn->peer_refresh_support = 1; break; - case 65: + + case 65: /* AS4 capability, RFC 4893 */ if (cl != 4) goto err; conn->peer_as4_support = 1; @@ -709,7 +784,7 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len) bgp_schedule_packet(conn, PKT_KEEPALIVE); bgp_start_timer(conn->hold_timer, conn->hold_time); - conn->state = BS_OPENCONFIRM; + bgp_conn_enter_openconfirm_state(conn); } #define DECODE_PREFIX(pp, ll) do { \ @@ -1160,8 +1235,14 @@ bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, int len) static void bgp_rx_packet(struct bgp_conn *conn, byte *pkt, unsigned len) { - DBG("BGP: Got packet %02x (%d bytes)\n", pkt[18], len); - switch (pkt[18]) + byte type = pkt[18]; + + DBG("BGP: Got packet %02x (%d bytes)\n", type, len); + + if (conn->bgp->p.mrtdump & MD_MESSAGES) + mrt_dump_bgp_packet(conn, pkt, len); + + switch (type) { case PKT_OPEN: return bgp_rx_open(conn, pkt, len); case PKT_UPDATE: return bgp_rx_update(conn, pkt, len); |