From: Donatas Abraitis Date: Sat, 30 Apr 2022 20:04:58 +0000 (+0300) Subject: bgpd: Implement CEASE/Hard Reset notification X-Git-Tag: base_8.3~103^2 X-Git-Url: https://git.puffer.fish/?a=commitdiff_plain;h=eea685b6d30b03b0924c0773b1f3563d95ee621f;p=mirror%2Ffrr.git bgpd: Implement CEASE/Hard Reset notification Also, add N-Bit (Notification) flag for Graceful Restart. This is a preparation for RFC8538. More information: https://datatracker.ietf.org/doc/html/rfc8538 Signed-off-by: Donatas Abraitis --- diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 49003e9428..0993d6de57 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -49,6 +49,7 @@ #include "bgpd/bgp_evpn_vty.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_flowspec.h" +#include "bgpd/bgp_packet.h" unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_neighbor_events; @@ -168,6 +169,7 @@ static const struct message bgp_notify_cease_msg[] = { {BGP_NOTIFY_CEASE_COLLISION_RESOLUTION, "/Connection Collision Resolution"}, {BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resources"}, + {BGP_NOTIFY_CEASE_HARD_RESET, "/Hard Reset"}, {0}}; static const struct message bgp_notify_route_refresh_msg[] = { @@ -520,7 +522,7 @@ const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, /* dump notify packet */ void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, - const char *direct) + const char *direct, bool hard_reset) { const char *subcode_str; const char *code_str; @@ -544,7 +546,8 @@ void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, if (msg_str) { zlog_info( - "%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) \"%s\"", + "%%NOTIFICATION%s: %s neighbor %s %d/%d (%s%s) \"%s\"", + hard_reset ? "(Hard Reset)" : "", strcmp(direct, "received") == 0 ? "received from" : "sent to", @@ -554,7 +557,8 @@ void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, } else { msg_str = bgp_notify->data ? bgp_notify->data : ""; zlog_info( - "%%NOTIFICATION: %s neighbor %s %d/%d (%s%s) %d bytes %s", + "%%NOTIFICATION%s: %s neighbor %s %d/%d (%s%s) %d bytes %s", + hard_reset ? "(Hard Reset)" : "", strcmp(direct, "received") == 0 ? "received from" : "sent to", diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h index d847fb84e7..cf6325ba36 100644 --- a/bgpd/bgp_debug.h +++ b/bgpd/bgp_debug.h @@ -170,7 +170,8 @@ extern bool bgp_dump_attr(struct attr *, char *, size_t); extern bool bgp_debug_peer_updout_enabled(char *host); extern const char *bgp_notify_code_str(char); extern const char *bgp_notify_subcode_str(char, char); -extern void bgp_notify_print(struct peer *, struct bgp_notify *, const char *); +extern void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, + const char *direct, bool hard_reset); extern const struct message bgp_status_msg[]; extern int bgp_debug_neighbor_events(struct peer *peer); diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index e78eb7453a..fe5f04ba11 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -2160,7 +2160,8 @@ static int bgp_establish(struct peer *peer) } else { /* Peer sends R-bit. In this case, we need to send * ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE to Zebra. */ - if (CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)) { + if (CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)) { FOREACH_AFI_SAFI (afi, safi) /* Send route processing complete message to RIB */ diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c index a994b536c4..1dc992fb94 100644 --- a/bgpd/bgp_memory.c +++ b/bgpd/bgp_memory.c @@ -145,3 +145,5 @@ DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service"); DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id"); DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function"); DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry"); + +DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message"); diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h index 76b2f9f56a..d4d7b0cf88 100644 --- a/bgpd/bgp_memory.h +++ b/bgpd/bgp_memory.h @@ -144,4 +144,6 @@ DECLARE_MTYPE(BGP_SRV6_FUNCTION); DECLARE_MTYPE(EVPN_REMOTE_IP); +DECLARE_MTYPE(BGP_NOTIFICATION); + #endif /* _QUAGGA_BGP_MEMORY_H */ diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index dc9f97f369..324c966b35 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -517,22 +517,39 @@ static int bgp_capability_restart(struct peer *peer, SET_FLAG(peer->cap, PEER_CAP_RESTART_RCV); restart_flag_time = stream_getw(s); + + /* The most significant bit is defined in [RFC4724] as + * the Restart State ("R") bit. + */ if (CHECK_FLAG(restart_flag_time, GRACEFUL_RESTART_R_BIT)) SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); else UNSET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); + /* The second most significant bit is defined in this + * document as the Graceful Notification ("N") bit. + */ + if (CHECK_FLAG(restart_flag_time, GRACEFUL_RESTART_N_BIT)) + SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); + else + UNSET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); + UNSET_FLAG(restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; if (bgp_debug_neighbor_events(peer)) { - zlog_debug("%s Peer has%srestarted. Restart Time : %d", - peer->host, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) - ? " " - : " not ", - peer->v_gr_restart); + zlog_debug( + "%s Peer has%srestarted. Restart Time: %d, N-bit set: %s", + peer->host, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) + ? " " + : " not ", + peer->v_gr_restart, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) + ? "yes" + : "no"); } while (stream_get_getp(s) + 4 <= end) { @@ -1418,10 +1435,12 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, restart_time = peer->bgp->restart_time; if (peer->bgp->t_startup) { SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); + SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); + SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending R-Bit for Peer :%s :", + zlog_debug("[BGP_GR] Sending R-Bit/N-Bit for peer: %s", peer->host); } diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index d359a872dc..1727b66041 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -88,6 +88,7 @@ struct graceful_restart_af { /* Graceful Restart */ #define GRACEFUL_RESTART_R_BIT 0x8000 +#define GRACEFUL_RESTART_N_BIT 0x4000 #define GRACEFUL_RESTART_F_BIT 0x80 /* Long-lived Graceful Restart */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index b0d852ee63..fc4c0b5154 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -712,6 +712,72 @@ static void bgp_write_notify(struct peer *peer) stream_free(s); } +/* + * Encapsulate an original BGP CEASE Notification into Hard Reset + */ +static uint8_t *bgp_notify_encapsulate_hard_reset(uint8_t code, uint8_t subcode, + uint8_t *data, size_t datalen) +{ + uint8_t *message = XCALLOC(MTYPE_BGP_NOTIFICATION, datalen + 2); + + /* ErrCode */ + message[0] = code; + /* Subcode */ + message[1] = subcode; + /* Data */ + if (datalen) + memcpy(message + 2, data, datalen); + + return message; +} + +/* + * Decapsulate an original BGP CEASE Notification from Hard Reset + */ +struct bgp_notify bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify) +{ + struct bgp_notify bn = {}; + + bn.code = notify->raw_data[0]; + bn.subcode = notify->raw_data[1]; + bn.length = notify->length - 2; + + bn.raw_data = XCALLOC(MTYPE_BGP_NOTIFICATION, bn.length); + memcpy(bn.raw_data, notify->raw_data + 2, bn.length); + + return bn; +} + +/* + * Check if to send BGP CEASE Notification/Hard Reset? + */ +bool bgp_notify_is_hard_reset(struct peer *peer, uint8_t code, uint8_t subcode) +{ + /* When the "N" bit has been exchanged, a Hard Reset message is used to + * indicate to the peer that the session is to be fully terminated. + */ + if (!CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) || + !CHECK_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV)) + return false; + + /* + * https://datatracker.ietf.org/doc/html/rfc8538#section-5.1 + */ + if (code == BGP_NOTIFY_CEASE || code == BGP_NOTIFY_HOLD_ERR) { + switch (subcode) { + case BGP_NOTIFY_CEASE_MAX_PREFIX: + case BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN: + case BGP_NOTIFY_CEASE_PEER_UNCONFIG: + case BGP_NOTIFY_CEASE_HARD_RESET: + return true; + default: + break; + } + } + + return false; +} + /* * Creates a BGP Notify and appends it to the peer's output queue. * @@ -736,6 +802,7 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code, uint8_t sub_code, uint8_t *data, size_t datalen) { struct stream *s; + bool hard_reset = bgp_notify_is_hard_reset(peer, code, sub_code); /* Lock I/O mutex to prevent other threads from pushing packets */ frr_mutex_lock_autounlock(&peer->io_mtx); @@ -747,13 +814,25 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code, /* Make notify packet. */ bgp_packet_set_marker(s, BGP_MSG_NOTIFY); - /* Set notify packet values. */ - stream_putc(s, code); /* BGP notify code */ - stream_putc(s, sub_code); /* BGP notify sub_code */ + /* Check if we should send Hard Reset Notification or not */ + if (hard_reset) { + uint8_t *hard_reset_message = bgp_notify_encapsulate_hard_reset( + code, sub_code, data, datalen); - /* If notify data is present. */ - if (data) - stream_write(s, data, datalen); + /* Hard Reset encapsulates another NOTIFICATION message + * in its data portion. + */ + stream_putc(s, BGP_NOTIFY_CEASE); + stream_putc(s, BGP_NOTIFY_CEASE_HARD_RESET); + stream_write(s, hard_reset_message, datalen + 2); + + XFREE(MTYPE_BGP_NOTIFICATION, hard_reset_message); + } else { + stream_putc(s, code); + stream_putc(s, sub_code); + if (data) + stream_write(s, data, datalen); + } /* Set BGP packet length. */ bgp_packet_set_size(s); @@ -808,7 +887,7 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code, bgp_notify.length); } } - bgp_notify_print(peer, &bgp_notify, "sending"); + bgp_notify_print(peer, &bgp_notify, "sending", hard_reset); if (bgp_notify.data) { XFREE(MTYPE_TMP, bgp_notify.data); @@ -1894,27 +1973,42 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) */ static int bgp_notify_receive(struct peer *peer, bgp_size_t size) { - struct bgp_notify bgp_notify; + struct bgp_notify outer; + struct bgp_notify inner; + bool hard_reset = false; if (peer->notify.data) { - XFREE(MTYPE_TMP, peer->notify.data); + XFREE(MTYPE_BGP_NOTIFICATION, peer->notify.data); peer->notify.length = 0; } - bgp_notify.code = stream_getc(peer->curr); - bgp_notify.subcode = stream_getc(peer->curr); - bgp_notify.length = size - 2; - bgp_notify.data = NULL; - bgp_notify.raw_data = NULL; + outer.code = stream_getc(peer->curr); + outer.subcode = stream_getc(peer->curr); + outer.length = size - 2; + outer.data = NULL; + outer.raw_data = NULL; + if (outer.length) { + outer.raw_data = XMALLOC(MTYPE_BGP_NOTIFICATION, outer.length); + memcpy(outer.raw_data, stream_pnt(peer->curr), outer.length); + } + + hard_reset = bgp_notify_is_hard_reset(peer, outer.code, outer.subcode); + if (hard_reset && outer.length) { + inner = bgp_notify_decapsulate_hard_reset(&outer); + peer->notify.hard_reset = true; + } else { + inner = outer; + } /* Preserv notify code and sub code. */ - peer->notify.code = bgp_notify.code; - peer->notify.subcode = bgp_notify.subcode; + peer->notify.code = inner.code; + peer->notify.subcode = inner.subcode; /* For further diagnostic record returned Data. */ - if (bgp_notify.length) { - peer->notify.length = size - 2; - peer->notify.data = XMALLOC(MTYPE_TMP, size - 2); - memcpy(peer->notify.data, stream_pnt(peer->curr), size - 2); + if (inner.length) { + peer->notify.length = inner.length; + peer->notify.data = + XMALLOC(MTYPE_BGP_NOTIFICATION, inner.length); + memcpy(peer->notify.data, inner.raw_data, inner.length); } /* For debug */ @@ -1923,32 +2017,35 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size) int first = 0; char c[4]; - if (bgp_notify.length) { - bgp_notify.data = - XMALLOC(MTYPE_TMP, bgp_notify.length * 3); - for (i = 0; i < bgp_notify.length; i++) + if (inner.length) { + inner.data = XMALLOC(MTYPE_BGP_NOTIFICATION, + inner.length * 3); + for (i = 0; i < inner.length; i++) if (first) { snprintf(c, sizeof(c), " %02x", stream_getc(peer->curr)); - strlcat(bgp_notify.data, c, - bgp_notify.length * 3); + strlcat(inner.data, c, + inner.length * 3); } else { first = 1; snprintf(c, sizeof(c), "%02x", stream_getc(peer->curr)); - strlcpy(bgp_notify.data, c, - bgp_notify.length * 3); + strlcpy(inner.data, c, + inner.length * 3); } - bgp_notify.raw_data = (uint8_t *)peer->notify.data; } - bgp_notify_print(peer, &bgp_notify, "received"); - if (bgp_notify.data) { - XFREE(MTYPE_TMP, bgp_notify.data); - bgp_notify.length = 0; + bgp_notify_print(peer, &inner, "received", hard_reset); + if (inner.data) { + XFREE(MTYPE_BGP_NOTIFICATION, inner.data); + inner.length = 0; + } + if (outer.length) { + XFREE(MTYPE_BGP_NOTIFICATION, outer.data); + outer.length = 0; } } @@ -1961,8 +2058,8 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size) in that case we fallback to open without the capability option. But this done in bgp_stop. We just mark it here to avoid changing the fsm tables. */ - if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR - && bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM) + if (inner.code == BGP_NOTIFY_OPEN_ERR && + inner.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM) UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); bgp_peer_gr_flags_update(peer); diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index 8c2de6d622..2fd7ff64d4 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -86,5 +86,9 @@ extern void bgp_send_delayed_eor(struct bgp *bgp); /* Task callback to handle socket error encountered in the io pthread */ void bgp_packet_process_error(struct thread *thread); +extern struct bgp_notify +bgp_notify_decapsulate_hard_reset(struct bgp_notify *notify); +extern bool bgp_notify_is_hard_reset(struct peer *peer, uint8_t code, + uint8_t subcode); #endif /* _QUAGGA_BGP_PACKET_H */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index bdd3164600..0cbb341ff3 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -10052,6 +10052,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, json_object_string_add(json_peer, "lastNotificationReason", errorcodesubcode_str); + json_object_boolean_add(json_peer, + "lastNotificationHardReset", + peer->notify.hard_reset); if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED && peer->notify.code == BGP_NOTIFY_CEASE && (peer->notify.subcode @@ -10085,11 +10088,16 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer, subcode_str = bgp_notify_subcode_str(peer->notify.code, peer->notify.subcode); - vty_out(vty, " Notification %s (%s%s)\n", + vty_out(vty, " Notification %s (%s%s%s)\n", peer->last_reset == PEER_DOWN_NOTIFY_SEND - ? "sent" - : "received", - code_str, subcode_str); + ? "sent" + : "received", + code_str, subcode_str, + peer->notify.hard_reset + ? bgp_notify_subcode_str( + BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_HARD_RESET) + : ""); } else { vty_out(vty, " %s\n", peer_down_str[(int)peer->last_reset]); @@ -11246,36 +11254,27 @@ static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p, } } -static void bgp_show_neighnor_graceful_restart_rbit(struct vty *vty, - struct peer *p, - bool use_json, - json_object *json) +static void bgp_show_neighnor_graceful_restart_flags(struct vty *vty, + struct peer *p, + bool use_json, + json_object *json) { - bool rbit_status = false; - - if (!use_json) - vty_out(vty, "\n R bit: "); + bool rbit = false; + bool nbit = false; if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) && (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) && (peer_established(p))) { - - if (CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)) - rbit_status = true; - else - rbit_status = false; + rbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); + nbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV); } - if (rbit_status) { - if (use_json) - json_object_boolean_true_add(json, "rBit"); - else - vty_out(vty, "True\n"); + if (use_json) { + json_object_boolean_add(json, "rBit", rbit); + json_object_boolean_add(json, "nBit", nbit); } else { - if (use_json) - json_object_boolean_false_add(json, "rBit"); - else - vty_out(vty, "False\n"); + vty_out(vty, "\n R bit: %s", rbit ? "True" : "False"); + vty_out(vty, "\n N bit: %s\n", nbit ? "True" : "False"); } } diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index 4b393275d6..143d3c1ac5 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -59,19 +59,18 @@ struct bgp; "V AS LocalAS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc\n" #define BGP_SHOW_SUMMARY_HEADER_FAILED "EstdCnt DropCnt ResetTime Reason\n" -#define BGP_SHOW_PEER_GR_CAPABILITY( \ - vty, p, use_json, json) \ - do { \ - bgp_show_neighbor_graceful_restart_local_mode( \ - vty, p, use_json, json); \ - bgp_show_neighbor_graceful_restart_remote_mode( \ - vty, p, use_json, json); \ - bgp_show_neighnor_graceful_restart_rbit( \ - vty, p, use_json, json); \ - bgp_show_neighbor_graceful_restart_time( \ - vty, p, use_json, json); \ - bgp_show_neighbor_graceful_restart_capability_per_afi_safi(\ - vty, p, use_json, json); \ +#define BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json) \ + do { \ + bgp_show_neighbor_graceful_restart_local_mode(vty, p, \ + use_json, json); \ + bgp_show_neighbor_graceful_restart_remote_mode( \ + vty, p, use_json, json); \ + bgp_show_neighnor_graceful_restart_flags(vty, p, use_json, \ + json); \ + bgp_show_neighbor_graceful_restart_time(vty, p, use_json, \ + json); \ + bgp_show_neighbor_graceful_restart_capability_per_afi_safi( \ + vty, p, use_json, json); \ } while (0) #define VTY_BGP_GR_DEFINE_LOOP_VARIABLE \ diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index a2361758dc..38fc51f507 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1153,7 +1153,7 @@ static void peer_free(struct peer *peer) XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if); - XFREE(MTYPE_TMP, peer->notify.data); + XFREE(MTYPE_BGP_NOTIFICATION, peer->notify.data); memset(&peer->notify, 0, sizeof(struct bgp_notify)); if (peer->clear_node_queue) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index aee5ce35d7..e43c529f35 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -819,6 +819,7 @@ struct bgp_notify { char *data; bgp_size_t length; uint8_t *raw_data; + bool hard_reset; }; /* Next hop self address. */ @@ -1192,6 +1193,10 @@ struct peer { #define PEER_CAP_EXTENDED_MESSAGE_RCV (1U << 20) #define PEER_CAP_LLGR_ADV (1U << 21) #define PEER_CAP_LLGR_RCV (1U << 22) +/* sent graceful-restart notification (N) bit */ +#define PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV (1U << 23) +/* received graceful-restart notification (N) bit */ +#define PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV (1U << 24) /* Capability flags (reset in bgp_stop) */ uint32_t af_cap[AFI_MAX][SAFI_MAX]; @@ -1852,6 +1857,7 @@ struct bgp_nlri { #define BGP_NOTIFY_CEASE_CONFIG_CHANGE 6 #define BGP_NOTIFY_CEASE_COLLISION_RESOLUTION 7 #define BGP_NOTIFY_CEASE_OUT_OF_RESOURCE 8 +#define BGP_NOTIFY_CEASE_HARD_RESET 9 /* BGP_NOTIFY_ROUTE_REFRESH_ERR sub codes (RFC 7313). */ #define BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN 1