summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2010-01-03 12:17:52 +0100
committerOndrej Zajicek <santiago@crfreenet.org>2010-01-03 12:17:52 +0100
commitcf31112f0d7618464097f71228f84bd534f1bc0f (patch)
tree68f7fa93bd2154a16169b4db3dc9c16e51c2e84f /proto/bgp
parent610bb3cff05f6d5b09c77724bc97295b809d15e2 (diff)
Implements MRTdump feature.
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/bgp.c29
-rw-r--r--proto/bgp/bgp.h8
-rw-r--r--proto/bgp/packets.c105
3 files changed, 124 insertions, 18 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 3cbcb6d7..215dc817 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 7cbd6557..24d69741 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 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);