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:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user