From cf31112f0d7618464097f71228f84bd534f1bc0f Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Sun, 3 Jan 2010 12:17:52 +0100 Subject: Implements MRTdump feature. --- proto/bgp/bgp.c | 29 ++++++++++++--- proto/bgp/bgp.h | 8 ++++ proto/bgp/packets.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 124 insertions(+), 18 deletions(-) (limited to 'proto/bgp') diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c index 3cbcb6d..215dc81 100644 --- a/proto/bgp/bgp.c +++ b/proto/bgp/bgp.c @@ -313,6 +313,22 @@ bgp_stop(struct bgp_proto *p, unsigned subcode) ev_schedule(p->event); } +static inline void +bgp_conn_set_state(struct bgp_conn *conn, unsigned new_state) +{ + if (conn->bgp->p.mrtdump & MD_STATES) + mrt_dump_bgp_state_change(conn, conn->state, new_state); + + conn->state = new_state; +} + +void +bgp_conn_enter_openconfirm_state(struct bgp_conn *conn) +{ + /* Really, most of the work is done in bgp_rx_open(). */ + bgp_conn_set_state(conn, BS_OPENCONFIRM); +} + void bgp_conn_enter_established_state(struct bgp_conn *conn) { @@ -325,7 +341,7 @@ bgp_conn_enter_established_state(struct bgp_conn *conn) p->last_error_class = 0; p->last_error_code = 0; bgp_attr_init(conn->bgp); - conn->state = BS_ESTABLISHED; + bgp_conn_set_state(conn, BS_ESTABLISHED); proto_notify_state(&p->p, PS_UP); } @@ -345,7 +361,7 @@ bgp_conn_enter_close_state(struct bgp_conn *conn) struct bgp_proto *p = conn->bgp; int os = conn->state; - conn->state = BS_CLOSE; + bgp_conn_set_state(conn, BS_CLOSE); tm_stop(conn->hold_timer); tm_stop(conn->keepalive_timer); conn->sk->rx_hook = NULL; @@ -361,7 +377,7 @@ bgp_conn_enter_idle_state(struct bgp_conn *conn) int os = conn->state; bgp_close_conn(conn); - conn->state = BS_IDLE; + bgp_conn_set_state(conn, BS_IDLE); ev_schedule(p->event); if (os == BS_ESTABLISHED) @@ -374,13 +390,14 @@ bgp_send_open(struct bgp_conn *conn) conn->start_state = conn->bgp->start_state; conn->want_as4_support = conn->bgp->cf->enable_as4 && (conn->start_state != BSS_CONNECT_NOCAP); conn->peer_as4_support = 0; // Default value, possibly changed by receiving capability. + conn->advertised_as = 0; DBG("BGP: Sending open\n"); conn->sk->rx_hook = bgp_rx; conn->sk->tx_hook = bgp_tx; tm_stop(conn->connect_retry_timer); bgp_schedule_packet(conn, PKT_OPEN); - conn->state = BS_OPENSENT; + bgp_conn_set_state(conn, BS_OPENSENT); bgp_start_timer(conn->hold_timer, conn->bgp->cf->initial_hold_time); } @@ -490,7 +507,7 @@ bgp_active(struct bgp_proto *p) BGP_TRACE(D_EVENTS, "Connect delayed by %d seconds", delay); bgp_setup_conn(p, conn); - conn->state = BS_ACTIVE; + bgp_conn_set_state(conn, BS_ACTIVE); bgp_start_timer(conn->connect_retry_timer, delay); } @@ -539,7 +556,7 @@ bgp_connect(struct bgp_proto *p) /* Enter Connect state and start establishing c BGP_TRACE(D_EVENTS, "Connecting to %I from local address %I", s->daddr, s->saddr); bgp_setup_conn(p, conn); bgp_setup_sk(p, conn, s); - conn->state = BS_CONNECT; + bgp_conn_set_state(conn, BS_CONNECT); if (sk_open(s)) { bgp_sock_err(s, 0); diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 7cbd655..24d6974 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -138,6 +138,7 @@ void bgp_check(struct bgp_config *c); void bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int len); void bgp_close_conn(struct bgp_conn *c); void bgp_update_startup_delay(struct bgp_proto *p); +void bgp_conn_enter_openconfirm_state(struct bgp_conn *conn); void bgp_conn_enter_established_state(struct bgp_conn *conn); void bgp_conn_enter_close_state(struct bgp_conn *conn); void bgp_conn_enter_idle_state(struct bgp_conn *conn); @@ -189,6 +190,7 @@ inline static void bgp_attach_attr_ip(struct ea_list **to, struct linpool *pool, /* packets.c */ +void mrt_dump_bgp_state_change(struct bgp_conn *conn, unsigned old, unsigned new); void bgp_schedule_packet(struct bgp_conn *conn, int type); void bgp_kick_tx(void *vconn); void bgp_tx(struct birdsock *sk); @@ -294,4 +296,10 @@ void bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsi #define BGP_AF_IPV4 1 #define BGP_AF_IPV6 2 +#ifdef IPV6 +#define BGP_AF BGP_AF_IPV6 +#else +#define BGP_AF BGP_AF_IPV4 +#endif + #endif diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c index 91b4792..03cc4ee 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); -- cgit v1.2.3