summaryrefslogtreecommitdiff
path: root/proto/bgp
diff options
context:
space:
mode:
authorOndrej Zajicek (work) <santiago@crfreenet.org>2017-09-19 19:55:37 +0200
committerOndrej Zajicek (work) <santiago@crfreenet.org>2017-09-19 19:57:52 +0200
commitcd1d99611e445c9fe2452d05627ccfc624f35c39 (patch)
treeeeae5838682bbc556ebf291423505a77164192e2 /proto/bgp
parent7b2c5f3d2826e3175bf31b1c36056c9efc587a2b (diff)
BGP: Shutdown communication (RFC 8203)
The patch implements BGP Administrative Shutdown Communication (RFC 8203) allowing BGP operators to pass messages related to BGP session administrative shutdown/restart. It handles both transmit and receive of shutdown messages. Messages are logged and may be displayed by show protocol all command. Thanks to Job Snijders for the basic patch.
Diffstat (limited to 'proto/bgp')
-rw-r--r--proto/bgp/bgp.c48
-rw-r--r--proto/bgp/bgp.h2
-rw-r--r--proto/bgp/packets.c58
3 files changed, 81 insertions, 27 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index 8a6b2f02..b99672f5 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -290,7 +290,7 @@ bgp_update_startup_delay(struct bgp_proto *p)
}
static void
-bgp_graceful_close_conn(struct bgp_conn *conn, unsigned subcode)
+bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode, byte *data, uint len)
{
switch (conn->state)
{
@@ -304,7 +304,7 @@ bgp_graceful_close_conn(struct bgp_conn *conn, unsigned subcode)
case BS_OPENSENT:
case BS_OPENCONFIRM:
case BS_ESTABLISHED:
- bgp_error(conn, 6, subcode, NULL, 0);
+ bgp_error(conn, 6, subcode, data, len);
return;
default:
bug("bgp_graceful_close_conn: Unknown state %d", conn->state);
@@ -340,11 +340,11 @@ bgp_decision(void *vp)
}
void
-bgp_stop(struct bgp_proto *p, unsigned subcode)
+bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len)
{
proto_notify_state(&p->p, PS_STOP);
- bgp_graceful_close_conn(&p->outgoing_conn, subcode);
- bgp_graceful_close_conn(&p->incoming_conn, subcode);
+ bgp_graceful_close_conn(&p->outgoing_conn, subcode, data, len);
+ bgp_graceful_close_conn(&p->incoming_conn, subcode, data, len);
ev_schedule(p->event);
}
@@ -420,7 +420,7 @@ bgp_conn_leave_established_state(struct bgp_proto *p)
bgp_free_bucket_table(p);
if (p->p.proto_state == PS_UP)
- bgp_stop(p, 0);
+ bgp_stop(p, 0, NULL, 0);
}
void
@@ -516,7 +516,7 @@ bgp_graceful_restart_timeout(timer *t)
struct bgp_proto *p = t->data;
BGP_TRACE(D_EVENTS, "Neighbor graceful restart timeout");
- bgp_stop(p, 0);
+ bgp_stop(p, 0, NULL, 0);
}
@@ -973,7 +973,7 @@ bgp_neigh_notify(neighbor *n)
BGP_TRACE(D_EVENTS, "Neighbor lost");
bgp_store_error(p, NULL, BE_MISC, BEM_NEIGHBOR_LOST);
/* Perhaps also run bgp_update_startup_delay(p)? */
- bgp_stop(p, 0);
+ bgp_stop(p, 0, NULL, 0);
}
}
else if (p->cf->check_link && !(n->iface->flags & IF_LINK_UP))
@@ -984,7 +984,7 @@ bgp_neigh_notify(neighbor *n)
bgp_store_error(p, NULL, BE_MISC, BEM_LINK_DOWN);
if (ps == PS_UP)
bgp_update_startup_delay(p);
- bgp_stop(p, 0);
+ bgp_stop(p, 0, NULL, 0);
}
}
else
@@ -1009,7 +1009,7 @@ bgp_bfd_notify(struct bfd_request *req)
bgp_store_error(p, NULL, BE_MISC, BEM_BFD_DOWN);
if (ps == PS_UP)
bgp_update_startup_delay(p);
- bgp_stop(p, 0);
+ bgp_stop(p, 0, NULL, 0);
}
}
@@ -1196,7 +1196,11 @@ static int
bgp_shutdown(struct proto *P)
{
struct bgp_proto *p = (struct bgp_proto *) P;
- unsigned subcode = 0;
+ uint subcode = 0;
+
+ char *message = NULL;
+ byte *data = NULL;
+ uint len = 0;
BGP_TRACE(D_EVENTS, "Shutdown requested");
@@ -1214,10 +1218,12 @@ bgp_shutdown(struct proto *P)
case PDC_CMD_DISABLE:
case PDC_CMD_SHUTDOWN:
subcode = 2; // Errcode 6, 2 - administrative shutdown
+ message = P->message;
break;
case PDC_CMD_RESTART:
subcode = 4; // Errcode 6, 4 - administrative reset
+ message = P->message;
break;
case PDC_RX_LIMIT_HIT:
@@ -1242,8 +1248,22 @@ bgp_shutdown(struct proto *P)
bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
p->startup_delay = 0;
- done:
- bgp_stop(p, subcode);
+ /* RFC 8203 - shutdown communication */
+ if (message)
+ {
+ uint msg_len = strlen(message);
+ msg_len = MIN(msg_len, 128);
+
+ /* Buffer will be freed automatically by protocol shutdown */
+ data = mb_alloc(p->p.pool, msg_len + 1);
+ len = msg_len + 1;
+
+ data[0] = msg_len;
+ memcpy(data+1, message, msg_len);
+ }
+
+done:
+ bgp_stop(p, subcode, data, len);
return p->p.proto_state;
}
@@ -1433,7 +1453,7 @@ bgp_error(struct bgp_conn *c, unsigned code, unsigned subcode, byte *data, int l
if (code != 6)
{
bgp_update_startup_delay(p);
- bgp_stop(p, 0);
+ bgp_stop(p, 0, NULL, 0);
}
}
diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h
index e47a0eb1..22a150ab 100644
--- a/proto/bgp/bgp.h
+++ b/proto/bgp/bgp.h
@@ -212,7 +212,7 @@ void bgp_graceful_restart_done(struct bgp_proto *p);
void bgp_refresh_begin(struct bgp_proto *p);
void bgp_refresh_end(struct bgp_proto *p);
void bgp_store_error(struct bgp_proto *p, struct bgp_conn *c, u8 class, u32 code);
-void bgp_stop(struct bgp_proto *p, unsigned subcode);
+void bgp_stop(struct bgp_proto *p, uint subcode, byte *data, uint len);
struct rte_source *bgp_find_source(struct bgp_proto *p, u32 path_id);
struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
diff --git a/proto/bgp/packets.c b/proto/bgp/packets.c
index ab87bdcc..af3b15b5 100644
--- a/proto/bgp/packets.c
+++ b/proto/bgp/packets.c
@@ -1494,38 +1494,72 @@ bgp_error_dsc(unsigned code, unsigned subcode)
return buff;
}
+/* RFC 8203 - shutdown communication message */
+static int
+bgp_handle_message(struct bgp_proto *p, byte *data, uint len, byte **bp)
+{
+ byte *msg = data + 1;
+ uint msg_len = data[0];
+ uint i;
+
+ /* Handle zero length message */
+ if (msg_len == 0)
+ return 1;
+
+ /* Handle proper message */
+ if ((msg_len > 128) && (msg_len + 1 > len))
+ return 0;
+
+ /* Some elementary cleanup */
+ for (i = 0; i < msg_len; i++)
+ if (msg[i] < ' ')
+ msg[i] = ' ';
+
+ proto_set_message(&p->p, msg, msg_len);
+ *bp += bsprintf(*bp, ": \"%s\"", p->p.message);
+ return 1;
+}
+
void
bgp_log_error(struct bgp_proto *p, u8 class, char *msg, unsigned code, unsigned subcode, byte *data, unsigned len)
{
- const byte *name;
- byte *t, argbuf[36];
+ byte argbuf[256], *t = argbuf;
unsigned i;
/* Don't report Cease messages generated by myself */
if (code == 6 && class == BE_BGP_TX)
return;
- name = bgp_error_dsc(code, subcode);
- t = argbuf;
+ /* Reset shutdown message */
+ if ((code == 6) && ((subcode == 2) || (subcode == 4)))
+ proto_set_message(&p->p, NULL, 0);
+
if (len)
{
- *t++ = ':';
- *t++ = ' ';
-
+ /* Bad peer AS - we would like to print the AS */
if ((code == 2) && (subcode == 2) && ((len == 2) || (len == 4)))
{
- /* Bad peer AS - we would like to print the AS */
- t += bsprintf(t, "%d", (len == 2) ? get_u16(data) : get_u32(data));
+ t += bsprintf(t, ": %u", (len == 2) ? get_u16(data) : get_u32(data));
goto done;
}
+
+ /* RFC 8203 - shutdown communication */
+ if (((code == 6) && ((subcode == 2) || (subcode == 4))))
+ if (bgp_handle_message(p, data, len, &t))
+ goto done;
+
+ *t++ = ':';
+ *t++ = ' ';
if (len > 16)
len = 16;
for (i=0; i<len; i++)
t += bsprintf(t, "%02x", data[i]);
}
- done:
+
+done:
*t = 0;
- log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, name, argbuf);
+ const byte *dsc = bgp_error_dsc(code, subcode);
+ log(L_REMOTE "%s: %s: %s%s", p->p.name, msg, dsc, argbuf);
}
static void
@@ -1571,7 +1605,7 @@ bgp_rx_notification(struct bgp_conn *conn, byte *pkt, uint len)
if (err)
{
bgp_update_startup_delay(p);
- bgp_stop(p, 0);
+ bgp_stop(p, 0, NULL, 0);
}
}