summaryrefslogtreecommitdiffstats
path: root/proto/bgp/packets.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r--proto/bgp/packets.c105
1 files changed, 93 insertions, 12 deletions
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);