1
0
mirror of https://gitlab.labs.nic.cz/labs/bird.git synced 2024-05-11 16:54:54 +00:00

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.
This commit is contained in:
Ondrej Zajicek (work)
2017-09-19 19:55:37 +02:00
parent 7b2c5f3d28
commit cd1d99611e
7 changed files with 149 additions and 54 deletions

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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);
}
}