From cd1d99611e445c9fe2452d05627ccfc624f35c39 Mon Sep 17 00:00:00 2001 From: "Ondrej Zajicek (work)" Date: Tue, 19 Sep 2017 19:55:37 +0200 Subject: 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. --- proto/bgp/bgp.c | 48 +++++++++++++++++++++++++++++++------------- proto/bgp/bgp.h | 2 +- proto/bgp/packets.c | 58 ++++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 81 insertions(+), 27 deletions(-) (limited to 'proto/bgp') 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; ip.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); } } -- cgit v1.2.3