summaryrefslogtreecommitdiff
path: root/proto/bgp/packets.c
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2018-11-20 17:38:19 +0100
committerOndrej Zajicek (work) <santiago@crfreenet.org>2018-11-20 17:45:35 +0100
commit863ecfc78538657e51f1ec67441aec32261aa405 (patch)
tree73b8628fbca9e04a554c5d08fe18bae4c647a51e /proto/bgp/packets.c
parent6712e77271fb3cb4a3c48cd7b027b39c5cea00a2 (diff)
The MRT protocol
The new MRT protocol is responsible for periodic RIB table dumps in the MRT format (RFC 6396). Also the existing code for BGP4MP MRT dumps is refactored and splitted between BGP to MRT protocols, will be more integrated into MRT in the future. Example: protocol mrt { table "*"; filename "%N_%F_%T.mrt"; period 60; } It is partially based on the old MRT code from Pavel Tvrdik.
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r--proto/bgp/packets.c180
1 files changed, 111 insertions, 69 deletions
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index ed1db04b..3be48c00 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -17,7 +17,7 @@
#include "nest/protocol.h"
#include "nest/route.h"
#include "nest/attrs.h"
-#include "nest/mrtdump.h"
+#include "proto/mrt/mrt.h"
#include "conf/conf.h"
#include "lib/unaligned.h"
#include "lib/flowspec.h"
@@ -90,91 +90,71 @@ get_af4(byte *buf)
return (get_u16(buf) << 16) | buf[3];
}
-/*
- * 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)
+static void
+init_mrt_bgp_data(struct bgp_conn *conn, struct mrt_bgp_data *d)
{
struct bgp_proto *p = conn->bgp;
- uint v4 = ipa_is_ip4(p->cf->remote_ip);
+ int p_ok = conn->state >= BS_OPENCONFIRM;
- if (as4)
- {
- put_u32(buf+0, p->remote_as);
- put_u32(buf+4, p->public_as);
- buf+=8;
- }
- else
- {
- put_u16(buf+0, (p->remote_as <= 0xFFFF) ? p->remote_as : AS_TRANS);
- put_u16(buf+2, (p->public_as <= 0xFFFF) ? p->public_as : AS_TRANS);
- buf+=4;
- }
+ memset(d, 0, sizeof(struct mrt_bgp_data));
+ d->peer_as = p->remote_as;
+ d->local_as = p->local_as;
+ d->index = (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0;
+ d->af = ipa_is_ip4(p->cf->remote_ip) ? BGP_AFI_IPV4 : BGP_AFI_IPV6;
+ d->peer_ip = conn->sk ? conn->sk->daddr : IPA_NONE;
+ d->local_ip = conn->sk ? conn->sk->saddr : IPA_NONE;
+ d->as4 = p_ok ? p->as4_session : 0;
+}
- put_u16(buf+0, (p->neigh && p->neigh->iface) ? p->neigh->iface->index : 0);
- put_u16(buf+2, v4 ? BGP_AFI_IPV4 : BGP_AFI_IPV6);
- buf+=4;
+static uint bgp_find_update_afi(byte *pos, uint len);
- if (v4)
- {
- buf = put_ip4(buf, conn->sk ? ipa_to_ip4(conn->sk->daddr) : IP4_NONE);
- buf = put_ip4(buf, conn->sk ? ipa_to_ip4(conn->sk->saddr) : IP4_NONE);
- }
- else
+static int
+bgp_estimate_add_path(struct bgp_proto *p, byte *pkt, uint len)
+{
+ /* No need to estimate it for other messages than UPDATE */
+ if (pkt[18] != PKT_UPDATE)
+ return 0;
+
+ /* 1 -> no channel, 2 -> all channels, 3 -> some channels */
+ if (p->summary_add_path_rx < 3)
+ return p->summary_add_path_rx == 2;
+
+ uint afi = bgp_find_update_afi(pkt, len);
+ struct bgp_channel *c = bgp_get_channel(p, afi);
+ if (!c)
{
- buf = put_ip6(buf, conn->sk ? ipa_to_ip6(conn->sk->daddr) : IP6_NONE);
- buf = put_ip6(buf, conn->sk ? ipa_to_ip6(conn->sk->saddr) : IP6_NONE);
+ /* Either frame error (if !afi) or unknown AFI/SAFI,
+ will be reported later in regular parsing */
+ BGP_TRACE(D_PACKETS, "MRT processing noticed invalid packet");
+ return 0;
}
- return buf;
+ return c->add_path_rx;
}
static void
-mrt_dump_bgp_packet(struct bgp_conn *conn, byte *pkt, uint len)
+bgp_dump_message(struct bgp_conn *conn, byte *pkt, uint len)
{
- byte *buf = alloca(128+len); /* 128 is enough for MRT headers */
- byte *bp = buf + MRTDUMP_HDR_LENGTH;
- int as4 = conn->bgp->as4_session;
+ struct mrt_bgp_data d;
+ init_mrt_bgp_data(conn, &d);
- 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);
-}
+ d.message = pkt;
+ d.msg_len = len;
+ d.add_path = bgp_estimate_add_path(conn->bgp, pkt, len);
-static inline u16
-convert_state(uint state)
-{
- /* Convert state from our BS_* values to values used in MRTDump */
- return (state == BS_CLOSE) ? 1 : state + 1;
+ mrt_dump_bgp_message(&d);
}
void
-mrt_dump_bgp_state_change(struct bgp_conn *conn, uint old, uint new)
+bgp_dump_state_change(struct bgp_conn *conn, uint old, uint new)
{
- byte buf[128];
- byte *bp = buf + MRTDUMP_HDR_LENGTH;
+ struct mrt_bgp_data d;
+ init_mrt_bgp_data(conn, &d);
+
+ d.old_state = old;
+ d.new_state = new;
- 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);
+ mrt_dump_bgp_state_change(&d);
}
static byte *
@@ -2135,6 +2115,7 @@ again: ;
.proto = p,
.channel = c,
.pool = bgp_linpool,
+ .mp_reach = (c->afi != BGP_AF_IPV4) || c->ext_next_hop,
.as4_session = p->as4_session,
.add_path = c->add_path_tx,
.mpls = c->desc->mpls,
@@ -2162,7 +2143,7 @@ again: ;
goto again;
}
- res = (c->afi == BGP_AF_IPV4) && !c->ext_next_hop ?
+ res = !s.mp_reach ?
bgp_create_ip_reach(&s, buck, buf, end):
bgp_create_mp_reach(&s, buck, buf, end);
@@ -2389,6 +2370,67 @@ done:
return;
}
+static uint
+bgp_find_update_afi(byte *pos, uint len)
+{
+ /*
+ * This is stripped-down version of bgp_rx_update(), bgp_decode_attrs() and
+ * bgp_decode_mp_[un]reach_nlri() used by MRT code in order to find out which
+ * AFI/SAFI is associated with incoming UPDATE. Returns 0 for framing errors.
+ */
+ if (len < 23)
+ return 0;
+
+ /* Assume there is no withrawn NLRI, read lengths and move to attribute list */
+ uint wlen = get_u16(pos + 19);
+ uint alen = get_u16(pos + 21);
+ ADVANCE(pos, len, 23);
+
+ /* Either non-zero withdrawn NLRI, non-zero reachable NLRI, or IPv4 End-of-RIB */
+ if ((wlen != 0) || (alen < len) || !alen)
+ return BGP_AF_IPV4;
+
+ if (alen > len)
+ return 0;
+
+ /* Process attribute list (alen == len) */
+ while (len)
+ {
+ if (len < 2)
+ return 0;
+
+ uint flags = pos[0];
+ uint code = pos[1];
+ ADVANCE(pos, len, 2);
+
+ uint ll = !(flags & BAF_EXT_LEN) ? 1 : 2;
+ if (len < ll)
+ return 0;
+
+ /* Read attribute length and move to attribute body */
+ alen = (ll == 1) ? get_u8(pos) : get_u16(pos);
+ ADVANCE(pos, len, ll);
+
+ if (len < alen)
+ return 0;
+
+ /* Found MP NLRI */
+ if ((code == BA_MP_REACH_NLRI) || (code == BA_MP_UNREACH_NLRI))
+ {
+ if (alen < 3)
+ return 0;
+
+ return BGP_AF(get_u16(pos), pos[2]);
+ }
+
+ /* Move to the next attribute */
+ ADVANCE(pos, len, alen);
+ }
+
+ /* No basic or MP NLRI, but there are some attributes -> error */
+ return 0;
+}
+
/*
* ROUTE-REFRESH
@@ -2890,7 +2932,7 @@ bgp_rx_packet(struct bgp_conn *conn, byte *pkt, uint len)
DBG("BGP: Got packet %02x (%d bytes)\n", type, len);
if (conn->bgp->p.mrtdump & MD_MESSAGES)
- mrt_dump_bgp_packet(conn, pkt, len);
+ bgp_dump_message(conn, pkt, len);
switch (type)
{