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 <donatas@opensourcerouting.org>
This commit is contained in:
Donatas Abraitis 2022-04-30 23:04:58 +03:00
parent 54394daa2d
commit eea685b6d3
13 changed files with 223 additions and 88 deletions

View file

@ -49,6 +49,7 @@
#include "bgpd/bgp_evpn_vty.h" #include "bgpd/bgp_evpn_vty.h"
#include "bgpd/bgp_vty.h" #include "bgpd/bgp_vty.h"
#include "bgpd/bgp_flowspec.h" #include "bgpd/bgp_flowspec.h"
#include "bgpd/bgp_packet.h"
unsigned long conf_bgp_debug_as4; unsigned long conf_bgp_debug_as4;
unsigned long conf_bgp_debug_neighbor_events; unsigned long conf_bgp_debug_neighbor_events;
@ -168,6 +169,7 @@ static const struct message bgp_notify_cease_msg[] = {
{BGP_NOTIFY_CEASE_COLLISION_RESOLUTION, {BGP_NOTIFY_CEASE_COLLISION_RESOLUTION,
"/Connection Collision Resolution"}, "/Connection Collision Resolution"},
{BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resources"}, {BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resources"},
{BGP_NOTIFY_CEASE_HARD_RESET, "/Hard Reset"},
{0}}; {0}};
static const struct message bgp_notify_route_refresh_msg[] = { 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 */ /* dump notify packet */
void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify, 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 *subcode_str;
const char *code_str; const char *code_str;
@ -544,7 +546,8 @@ void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify,
if (msg_str) { if (msg_str) {
zlog_info( 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 strcmp(direct, "received") == 0
? "received from" ? "received from"
: "sent to", : "sent to",
@ -554,7 +557,8 @@ void bgp_notify_print(struct peer *peer, struct bgp_notify *bgp_notify,
} else { } else {
msg_str = bgp_notify->data ? bgp_notify->data : ""; msg_str = bgp_notify->data ? bgp_notify->data : "";
zlog_info( 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 strcmp(direct, "received") == 0
? "received from" ? "received from"
: "sent to", : "sent to",

View file

@ -170,7 +170,8 @@ extern bool bgp_dump_attr(struct attr *, char *, size_t);
extern bool bgp_debug_peer_updout_enabled(char *host); extern bool bgp_debug_peer_updout_enabled(char *host);
extern const char *bgp_notify_code_str(char); extern const char *bgp_notify_code_str(char);
extern const char *bgp_notify_subcode_str(char, 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 const struct message bgp_status_msg[];
extern int bgp_debug_neighbor_events(struct peer *peer); extern int bgp_debug_neighbor_events(struct peer *peer);

View file

@ -2160,7 +2160,8 @@ static int bgp_establish(struct peer *peer)
} else { } else {
/* Peer sends R-bit. In this case, we need to send /* Peer sends R-bit. In this case, we need to send
* ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE to Zebra. */ * 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) FOREACH_AFI_SAFI (afi, safi)
/* Send route processing complete /* Send route processing complete
message to RIB */ message to RIB */

View file

@ -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_SID, "BGP srv6 segment-id");
DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function"); DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry"); DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");

View file

@ -144,4 +144,6 @@ DECLARE_MTYPE(BGP_SRV6_FUNCTION);
DECLARE_MTYPE(EVPN_REMOTE_IP); DECLARE_MTYPE(EVPN_REMOTE_IP);
DECLARE_MTYPE(BGP_NOTIFICATION);
#endif /* _QUAGGA_BGP_MEMORY_H */ #endif /* _QUAGGA_BGP_MEMORY_H */

View file

@ -517,22 +517,39 @@ static int bgp_capability_restart(struct peer *peer,
SET_FLAG(peer->cap, PEER_CAP_RESTART_RCV); SET_FLAG(peer->cap, PEER_CAP_RESTART_RCV);
restart_flag_time = stream_getw(s); 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)) if (CHECK_FLAG(restart_flag_time, GRACEFUL_RESTART_R_BIT))
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV);
else else
UNSET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV); 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); UNSET_FLAG(restart_flag_time, 0xF000);
peer->v_gr_restart = restart_flag_time; peer->v_gr_restart = restart_flag_time;
if (bgp_debug_neighbor_events(peer)) { if (bgp_debug_neighbor_events(peer)) {
zlog_debug("%s Peer has%srestarted. Restart Time : %d", zlog_debug(
"%s Peer has%srestarted. Restart Time: %d, N-bit set: %s",
peer->host, peer->host,
CHECK_FLAG(peer->cap, CHECK_FLAG(peer->cap,
PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)
? " " ? " "
: " not ", : " not ",
peer->v_gr_restart); peer->v_gr_restart,
CHECK_FLAG(peer->cap,
PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV)
? "yes"
: "no");
} }
while (stream_get_getp(s) + 4 <= end) { 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; restart_time = peer->bgp->restart_time;
if (peer->bgp->t_startup) { if (peer->bgp->t_startup) {
SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); 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_R_BIT_ADV);
SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV);
if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) 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); peer->host);
} }

View file

@ -88,6 +88,7 @@ struct graceful_restart_af {
/* Graceful Restart */ /* Graceful Restart */
#define GRACEFUL_RESTART_R_BIT 0x8000 #define GRACEFUL_RESTART_R_BIT 0x8000
#define GRACEFUL_RESTART_N_BIT 0x4000
#define GRACEFUL_RESTART_F_BIT 0x80 #define GRACEFUL_RESTART_F_BIT 0x80
/* Long-lived Graceful Restart */ /* Long-lived Graceful Restart */

View file

@ -712,6 +712,72 @@ static void bgp_write_notify(struct peer *peer)
stream_free(s); 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. * 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) uint8_t sub_code, uint8_t *data, size_t datalen)
{ {
struct stream *s; 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 */ /* Lock I/O mutex to prevent other threads from pushing packets */
frr_mutex_lock_autounlock(&peer->io_mtx); 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. */ /* Make notify packet. */
bgp_packet_set_marker(s, BGP_MSG_NOTIFY); bgp_packet_set_marker(s, BGP_MSG_NOTIFY);
/* Set notify packet values. */ /* Check if we should send Hard Reset Notification or not */
stream_putc(s, code); /* BGP notify code */ if (hard_reset) {
stream_putc(s, sub_code); /* BGP notify sub_code */ uint8_t *hard_reset_message = bgp_notify_encapsulate_hard_reset(
code, sub_code, data, datalen);
/* If notify data is present. */ /* 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) if (data)
stream_write(s, data, datalen); stream_write(s, data, datalen);
}
/* Set BGP packet length. */ /* Set BGP packet length. */
bgp_packet_set_size(s); 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.length);
} }
} }
bgp_notify_print(peer, &bgp_notify, "sending"); bgp_notify_print(peer, &bgp_notify, "sending", hard_reset);
if (bgp_notify.data) { if (bgp_notify.data) {
XFREE(MTYPE_TMP, 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) 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) { if (peer->notify.data) {
XFREE(MTYPE_TMP, peer->notify.data); XFREE(MTYPE_BGP_NOTIFICATION, peer->notify.data);
peer->notify.length = 0; peer->notify.length = 0;
} }
bgp_notify.code = stream_getc(peer->curr); outer.code = stream_getc(peer->curr);
bgp_notify.subcode = stream_getc(peer->curr); outer.subcode = stream_getc(peer->curr);
bgp_notify.length = size - 2; outer.length = size - 2;
bgp_notify.data = NULL; outer.data = NULL;
bgp_notify.raw_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. */ /* Preserv notify code and sub code. */
peer->notify.code = bgp_notify.code; peer->notify.code = inner.code;
peer->notify.subcode = bgp_notify.subcode; peer->notify.subcode = inner.subcode;
/* For further diagnostic record returned Data. */ /* For further diagnostic record returned Data. */
if (bgp_notify.length) { if (inner.length) {
peer->notify.length = size - 2; peer->notify.length = inner.length;
peer->notify.data = XMALLOC(MTYPE_TMP, size - 2); peer->notify.data =
memcpy(peer->notify.data, stream_pnt(peer->curr), size - 2); XMALLOC(MTYPE_BGP_NOTIFICATION, inner.length);
memcpy(peer->notify.data, inner.raw_data, inner.length);
} }
/* For debug */ /* For debug */
@ -1923,32 +2017,35 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
int first = 0; int first = 0;
char c[4]; char c[4];
if (bgp_notify.length) { if (inner.length) {
bgp_notify.data = inner.data = XMALLOC(MTYPE_BGP_NOTIFICATION,
XMALLOC(MTYPE_TMP, bgp_notify.length * 3); inner.length * 3);
for (i = 0; i < bgp_notify.length; i++) for (i = 0; i < inner.length; i++)
if (first) { if (first) {
snprintf(c, sizeof(c), " %02x", snprintf(c, sizeof(c), " %02x",
stream_getc(peer->curr)); stream_getc(peer->curr));
strlcat(bgp_notify.data, c, strlcat(inner.data, c,
bgp_notify.length * 3); inner.length * 3);
} else { } else {
first = 1; first = 1;
snprintf(c, sizeof(c), "%02x", snprintf(c, sizeof(c), "%02x",
stream_getc(peer->curr)); stream_getc(peer->curr));
strlcpy(bgp_notify.data, c, strlcpy(inner.data, c,
bgp_notify.length * 3); inner.length * 3);
} }
bgp_notify.raw_data = (uint8_t *)peer->notify.data;
} }
bgp_notify_print(peer, &bgp_notify, "received"); bgp_notify_print(peer, &inner, "received", hard_reset);
if (bgp_notify.data) { if (inner.data) {
XFREE(MTYPE_TMP, bgp_notify.data); XFREE(MTYPE_BGP_NOTIFICATION, inner.data);
bgp_notify.length = 0; 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. 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 But this done in bgp_stop. We just mark it here to avoid changing
the fsm tables. */ the fsm tables. */
if (bgp_notify.code == BGP_NOTIFY_OPEN_ERR if (inner.code == BGP_NOTIFY_OPEN_ERR &&
&& bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM) inner.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM)
UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN); UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
bgp_peer_gr_flags_update(peer); bgp_peer_gr_flags_update(peer);

View file

@ -86,5 +86,9 @@ extern void bgp_send_delayed_eor(struct bgp *bgp);
/* Task callback to handle socket error encountered in the io pthread */ /* Task callback to handle socket error encountered in the io pthread */
void bgp_packet_process_error(struct thread *thread); 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 */ #endif /* _QUAGGA_BGP_PACKET_H */

View file

@ -10052,6 +10052,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
json_object_string_add(json_peer, json_object_string_add(json_peer,
"lastNotificationReason", "lastNotificationReason",
errorcodesubcode_str); errorcodesubcode_str);
json_object_boolean_add(json_peer,
"lastNotificationHardReset",
peer->notify.hard_reset);
if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED if (peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED
&& peer->notify.code == BGP_NOTIFY_CEASE && peer->notify.code == BGP_NOTIFY_CEASE
&& (peer->notify.subcode && (peer->notify.subcode
@ -10085,11 +10088,16 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
subcode_str = subcode_str =
bgp_notify_subcode_str(peer->notify.code, bgp_notify_subcode_str(peer->notify.code,
peer->notify.subcode); 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 peer->last_reset == PEER_DOWN_NOTIFY_SEND
? "sent" ? "sent"
: "received", : "received",
code_str, subcode_str); code_str, subcode_str,
peer->notify.hard_reset
? bgp_notify_subcode_str(
BGP_NOTIFY_CEASE,
BGP_NOTIFY_CEASE_HARD_RESET)
: "");
} else { } else {
vty_out(vty, " %s\n", vty_out(vty, " %s\n",
peer_down_str[(int)peer->last_reset]); 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, static void bgp_show_neighnor_graceful_restart_flags(struct vty *vty,
struct peer *p, struct peer *p,
bool use_json, bool use_json,
json_object *json) json_object *json)
{ {
bool rbit_status = false; bool rbit = false;
bool nbit = false;
if (!use_json)
vty_out(vty, "\n R bit: ");
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)
&& (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) && (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV))
&& (peer_established(p))) { && (peer_established(p))) {
rbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV);
if (CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV)) nbit = CHECK_FLAG(p->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV);
rbit_status = true;
else
rbit_status = false;
} }
if (rbit_status) { if (use_json) {
if (use_json) json_object_boolean_add(json, "rBit", rbit);
json_object_boolean_true_add(json, "rBit"); json_object_boolean_add(json, "nBit", nbit);
else
vty_out(vty, "True\n");
} else { } else {
if (use_json) vty_out(vty, "\n R bit: %s", rbit ? "True" : "False");
json_object_boolean_false_add(json, "rBit"); vty_out(vty, "\n N bit: %s\n", nbit ? "True" : "False");
else
vty_out(vty, "False\n");
} }
} }

View file

@ -59,17 +59,16 @@ struct bgp;
"V AS LocalAS MsgRcvd MsgSent TblVer InQ OutQ Up/Down State/PfxRcd PfxSnt Desc\n" "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_SUMMARY_HEADER_FAILED "EstdCnt DropCnt ResetTime Reason\n"
#define BGP_SHOW_PEER_GR_CAPABILITY( \ #define BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json) \
vty, p, use_json, json) \
do { \ do { \
bgp_show_neighbor_graceful_restart_local_mode( \ bgp_show_neighbor_graceful_restart_local_mode(vty, p, \
vty, p, use_json, json); \ use_json, json); \
bgp_show_neighbor_graceful_restart_remote_mode( \ bgp_show_neighbor_graceful_restart_remote_mode( \
vty, p, use_json, json); \ vty, p, use_json, json); \
bgp_show_neighnor_graceful_restart_rbit( \ bgp_show_neighnor_graceful_restart_flags(vty, p, use_json, \
vty, p, use_json, json); \ json); \
bgp_show_neighbor_graceful_restart_time( \ bgp_show_neighbor_graceful_restart_time(vty, p, use_json, \
vty, p, use_json, json); \ json); \
bgp_show_neighbor_graceful_restart_capability_per_afi_safi( \ bgp_show_neighbor_graceful_restart_capability_per_afi_safi( \
vty, p, use_json, json); \ vty, p, use_json, json); \
} while (0) } while (0)

View file

@ -1153,7 +1153,7 @@ static void peer_free(struct peer *peer)
XFREE(MTYPE_PEER_UPDATE_SOURCE, peer->update_if); 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)); memset(&peer->notify, 0, sizeof(struct bgp_notify));
if (peer->clear_node_queue) if (peer->clear_node_queue)

View file

@ -819,6 +819,7 @@ struct bgp_notify {
char *data; char *data;
bgp_size_t length; bgp_size_t length;
uint8_t *raw_data; uint8_t *raw_data;
bool hard_reset;
}; };
/* Next hop self address. */ /* Next hop self address. */
@ -1192,6 +1193,10 @@ struct peer {
#define PEER_CAP_EXTENDED_MESSAGE_RCV (1U << 20) #define PEER_CAP_EXTENDED_MESSAGE_RCV (1U << 20)
#define PEER_CAP_LLGR_ADV (1U << 21) #define PEER_CAP_LLGR_ADV (1U << 21)
#define PEER_CAP_LLGR_RCV (1U << 22) #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) */ /* Capability flags (reset in bgp_stop) */
uint32_t af_cap[AFI_MAX][SAFI_MAX]; 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_CONFIG_CHANGE 6
#define BGP_NOTIFY_CEASE_COLLISION_RESOLUTION 7 #define BGP_NOTIFY_CEASE_COLLISION_RESOLUTION 7
#define BGP_NOTIFY_CEASE_OUT_OF_RESOURCE 8 #define BGP_NOTIFY_CEASE_OUT_OF_RESOURCE 8
#define BGP_NOTIFY_CEASE_HARD_RESET 9
/* BGP_NOTIFY_ROUTE_REFRESH_ERR sub codes (RFC 7313). */ /* BGP_NOTIFY_ROUTE_REFRESH_ERR sub codes (RFC 7313). */
#define BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN 1 #define BGP_NOTIFY_ROUTE_REFRESH_INVALID_MSG_LEN 1