diff options
Diffstat (limited to 'proto/bgp')
-rw-r--r-- | proto/bgp/bgp.c | 44 | ||||
-rw-r--r-- | proto/bgp/bgp.h | 2 | ||||
-rw-r--r-- | proto/bgp/packets.c | 58 |
3 files changed, 79 insertions, 25 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); } } diff --git a/proto/bgp/bgp.h b/proto/bgp/bgp.h index 3d940c22..40c4b3f0 100644 --- a/proto/bgp/bgp.h +++ b/proto/bgp/bgp.h @@ -437,7 +437,7 @@ void bgp_graceful_restart_done(struct bgp_channel *c); void bgp_refresh_begin(struct bgp_channel *c); void bgp_refresh_end(struct bgp_channel *c); 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 0e974746..038e89f9 100644 --- a/proto/bgp/packets.c +++ b/proto/bgp/packets.c @@ -2678,38 +2678,72 @@ bgp_error_dsc(uint code, uint 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, uint code, uint subcode, byte *data, uint len) { - const byte *name; - byte *t, argbuf[36]; + byte argbuf[256], *t = argbuf; uint 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, "%u", (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 @@ -2733,7 +2767,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); } } |