summaryrefslogtreecommitdiff
path: root/proto/bgp/packets.c
diff options
context:
space:
mode:
authorOndrej Zajicek <santiago@crfreenet.org>2015-03-29 18:27:13 +0200
committerOndrej Zajicek <santiago@crfreenet.org>2015-03-29 18:29:49 +0200
commit9aed29e605334d34d0e6a90fc172ee83d0274ad3 (patch)
tree349b424464aef43726f410d80e070f8955782a58 /proto/bgp/packets.c
parenta5a5a41e2ee51ad6dfef0ab24e07d6d9b16a4215 (diff)
BGP: Enhanced route refresh (RFC 7313) support
Also hook feed_done is renamed to feed_end.
Diffstat (limited to 'proto/bgp/packets.c')
-rw-r--r--proto/bgp/packets.c137
1 files changed, 120 insertions, 17 deletions
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index d34e7c56..2d2a84b3 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -22,6 +22,12 @@
#include "bgp.h"
+
+#define BGP_RR_REQUEST 0
+#define BGP_RR_BEGIN 1
+#define BGP_RR_END 2
+
+
static struct tbf rl_rcv_update = TBF_DEFAULT_LOG_LIMITS;
static struct tbf rl_snd_update = TBF_DEFAULT_LOG_LIMITS;
@@ -210,6 +216,15 @@ bgp_put_cap_add_path(struct bgp_proto *p, byte *buf)
}
static byte *
+bgp_put_cap_err(struct bgp_proto *p UNUSED, byte *buf)
+{
+ *buf++ = 70; /* Capability 70: Support for enhanced route refresh */
+ *buf++ = 0; /* Capability data length */
+ return buf;
+}
+
+
+static byte *
bgp_create_open(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
@@ -256,6 +271,9 @@ bgp_create_open(struct bgp_conn *conn, byte *buf)
if (p->cf->add_path)
cap = bgp_put_cap_add_path(p, cap);
+ if (p->cf->enable_refresh)
+ cap = bgp_put_cap_err(p, cap);
+
cap_len = cap - buf - 12;
if (cap_len > 0)
{
@@ -389,7 +407,7 @@ static byte *
bgp_create_end_mark(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
- BGP_TRACE(D_PACKETS, "Sending End-of-RIB");
+ BGP_TRACE(D_PACKETS, "Sending END-OF-RIB");
put_u32(buf, 0);
return buf+4;
@@ -568,7 +586,7 @@ static byte *
bgp_create_end_mark(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
- BGP_TRACE(D_PACKETS, "Sending End-of-RIB");
+ BGP_TRACE(D_PACKETS, "Sending END-OF-RIB");
put_u16(buf+0, 0);
put_u16(buf+2, 6); /* length 4-9 */
@@ -586,19 +604,49 @@ bgp_create_end_mark(struct bgp_conn *conn, byte *buf)
#endif
-static byte *
+static inline byte *
bgp_create_route_refresh(struct bgp_conn *conn, byte *buf)
{
struct bgp_proto *p = conn->bgp;
BGP_TRACE(D_PACKETS, "Sending ROUTE-REFRESH");
+ /* Original original route refresh request, RFC 2918 */
*buf++ = 0;
*buf++ = BGP_AF;
- *buf++ = 0; /* RFU */
- *buf++ = 1; /* and SAFI 1 */
+ *buf++ = BGP_RR_REQUEST;
+ *buf++ = 1; /* SAFI */
+ return buf;
+}
+
+static inline byte *
+bgp_create_begin_refresh(struct bgp_conn *conn, byte *buf)
+{
+ struct bgp_proto *p = conn->bgp;
+ BGP_TRACE(D_PACKETS, "Sending BEGIN-OF-RR");
+
+ /* Demarcation of beginning of route refresh (BoRR), RFC 7313 */
+ *buf++ = 0;
+ *buf++ = BGP_AF;
+ *buf++ = BGP_RR_BEGIN;
+ *buf++ = 1; /* SAFI */
return buf;
}
+static inline byte *
+bgp_create_end_refresh(struct bgp_conn *conn, byte *buf)
+{
+ struct bgp_proto *p = conn->bgp;
+ BGP_TRACE(D_PACKETS, "Sending END-OF-RR");
+
+ /* Demarcation of ending of route refresh (EoRR), RFC 7313 */
+ *buf++ = 0;
+ *buf++ = BGP_AF;
+ *buf++ = BGP_RR_END;
+ *buf++ = 1; /* SAFI */
+ return buf;
+}
+
+
static void
bgp_create_header(byte *buf, unsigned int len, unsigned int type)
{
@@ -666,24 +714,44 @@ bgp_fire_tx(struct bgp_conn *conn)
type = PKT_ROUTE_REFRESH;
end = bgp_create_route_refresh(conn, pkt);
}
+ else if (s & (1 << PKT_BEGIN_REFRESH))
+ {
+ s &= ~(1 << PKT_BEGIN_REFRESH);
+ type = PKT_ROUTE_REFRESH; /* BoRR is a subtype of RR */
+ end = bgp_create_begin_refresh(conn, pkt);
+ }
else if (s & (1 << PKT_UPDATE))
{
- end = bgp_create_update(conn, pkt);
type = PKT_UPDATE;
+ end = bgp_create_update(conn, pkt);
if (!end)
- {
+ {
+ /* No update to send, perhaps we need to send End-of-RIB or EoRR */
+
conn->packets_to_send = 0;
- if (!p->send_end_mark)
+ if (p->feed_state == BFS_LOADED)
+ {
+ type = PKT_UPDATE;
+ end = bgp_create_end_mark(conn, pkt);
+ }
+
+ else if (p->feed_state == BFS_REFRESHED)
+ {
+ type = PKT_ROUTE_REFRESH;
+ end = bgp_create_end_refresh(conn, pkt);
+ }
+
+ else /* Really nothing to send */
return 0;
- p->send_end_mark = 0;
- end = bgp_create_end_mark(conn, pkt);
+ p->feed_state = BFS_NONE;
}
}
else
return 0;
+
conn->packets_to_send = s;
bgp_create_header(buf, end - buf, type);
return sk_send(sk, end - buf);
@@ -737,7 +805,7 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
{
if (len < 2 || len < 2 + opt[1])
goto err;
-
+
cl = opt[1];
switch (opt[0])
@@ -780,7 +848,12 @@ bgp_parse_capabilities(struct bgp_conn *conn, byte *opt, int len)
conn->peer_add_path = opt[2+i+3];
if (conn->peer_add_path > ADD_PATH_FULL)
goto err;
+ break;
+ case 70: /* Enhanced route refresh capability, RFC 7313 */
+ if (cl != 0)
+ goto err;
+ conn->peer_enhanced_refresh_support = 1;
break;
/* We can safely ignore all other capabilities */
@@ -945,7 +1018,10 @@ bgp_rx_open(struct bgp_conn *conn, byte *pkt, int len)
static inline void
bgp_rx_end_mark(struct bgp_proto *p)
{
- BGP_TRACE(D_PACKETS, "Got End-of-RIB");
+ BGP_TRACE(D_PACKETS, "Got END-OF-RIB");
+
+ if (p->load_state == BFS_LOADING)
+ p->load_state = BFS_NONE;
if (p->p.gr_recovery)
proto_graceful_restart_unlock(&p->p);
@@ -1353,7 +1429,9 @@ static struct {
{ 6, 5, "Connection rejected" },
{ 6, 6, "Other configuration change" },
{ 6, 7, "Connection collision resolution" },
- { 6, 8, "Out of Resources" }
+ { 6, 8, "Out of Resources" },
+ { 7, 0, "Invalid ROUTE-REFRESH message" }, /* [RFC7313] */
+ { 7, 1, "Invalid ROUTE-REFRESH message length" } /* [RFC7313] */
};
/**
@@ -1484,22 +1562,47 @@ bgp_rx_route_refresh(struct bgp_conn *conn, byte *pkt, int len)
{
struct bgp_proto *p = conn->bgp;
- BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
-
if (conn->state != BS_ESTABLISHED)
{ bgp_error(conn, 5, fsm_err_subcode[conn->state], NULL, 0); return; }
if (!p->cf->enable_refresh)
{ bgp_error(conn, 1, 3, pkt+18, 1); return; }
- if (len != (BGP_HEADER_LENGTH + 4))
+ if (len < (BGP_HEADER_LENGTH + 4))
{ bgp_error(conn, 1, 2, pkt+16, 2); return; }
+ if (len > (BGP_HEADER_LENGTH + 4))
+ { bgp_error(conn, 7, 1, pkt, MIN(len, 2048)); return; }
+
/* FIXME - we ignore AFI/SAFI values, as we support
just one value and even an error code for an invalid
request is not defined */
- proto_request_feeding(&p->p);
+ /* RFC 7313 redefined reserved field as RR message subtype */
+ uint subtype = conn->peer_enhanced_refresh_support ? pkt[21] : BGP_RR_REQUEST;
+
+ switch (subtype)
+ {
+ case BGP_RR_REQUEST:
+ BGP_TRACE(D_PACKETS, "Got ROUTE-REFRESH");
+ proto_request_feeding(&p->p);
+ break;
+
+ case BGP_RR_BEGIN:
+ BGP_TRACE(D_PACKETS, "Got BEGIN-OF-RR");
+ bgp_refresh_begin(p);
+ break;
+
+ case BGP_RR_END:
+ BGP_TRACE(D_PACKETS, "Got END-OF-RR");
+ bgp_refresh_end(p);
+ break;
+
+ default:
+ log(L_WARN "%s: Got ROUTE-REFRESH message with unknown subtype %u, ignoring",
+ p->p.name, subtype);
+ break;
+ }
}