summaryrefslogtreecommitdiff
path: root/proto/bgp/bgp.c
diff options
context:
space:
mode:
Diffstat (limited to 'proto/bgp/bgp.c')
-rw-r--r--proto/bgp/bgp.c44
1 files changed, 32 insertions, 12 deletions
diff --git a/proto/bgp/bgp.c b/proto/bgp/bgp.c
index b0814791..30fe75ba 100644
--- a/proto/bgp/bgp.c
+++ b/proto/bgp/bgp.c
@@ -403,7 +403,7 @@ bgp_update_startup_delay(struct bgp_proto *p)
}
static void
-bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode)
+bgp_graceful_close_conn(struct bgp_conn *conn, uint subcode, byte *data, uint len)
{
switch (conn->state)
{
@@ -419,7 +419,7 @@ bgp_graceful_close_conn(struct bgp_conn *conn, uint 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:
@@ -459,11 +459,11 @@ bgp_decision(void *vp)
}
void
-bgp_stop(struct bgp_proto *p, uint 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);
}
@@ -606,7 +606,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
@@ -725,7 +725,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);
}
@@ -1125,7 +1125,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))
@@ -1136,7 +1136,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
@@ -1161,7 +1161,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);
}
}
@@ -1349,6 +1349,10 @@ bgp_shutdown(struct proto *P)
struct bgp_proto *p = (struct bgp_proto *) P;
uint subcode = 0;
+ char *message = NULL;
+ byte *data = NULL;
+ uint len = 0;
+
BGP_TRACE(D_EVENTS, "Shutdown requested");
switch (P->down_code)
@@ -1365,10 +1369,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:
@@ -1393,8 +1399,22 @@ bgp_shutdown(struct proto *P)
bgp_store_error(p, NULL, BE_MAN_DOWN, 0);
p->startup_delay = 0;
+ /* 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);
+ bgp_stop(p, subcode, data, len);
return p->p.proto_state;
}
@@ -1785,7 +1805,7 @@ bgp_error(struct bgp_conn *c, uint code, uint subcode, byte *data, int len)
if (code != 6)
{
bgp_update_startup_delay(p);
- bgp_stop(p, 0);
+ bgp_stop(p, 0, NULL, 0);
}
}