summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_debug.c55
-rw-r--r--bgpd/bgp_debug.h4
-rw-r--r--bgpd/bgp_fsm.c702
-rw-r--r--bgpd/bgp_fsm.h77
-rw-r--r--bgpd/bgp_io.c16
-rw-r--r--bgpd/bgp_main.c1
-rw-r--r--bgpd/bgp_network.c28
-rw-r--r--bgpd/bgp_open.c145
-rw-r--r--bgpd/bgp_packet.c108
-rw-r--r--bgpd/bgp_packet.h9
-rw-r--r--bgpd/bgp_route.c237
-rw-r--r--bgpd/bgp_route.h1
-rw-r--r--bgpd/bgp_table.c37
-rw-r--r--bgpd/bgp_table.h7
-rw-r--r--bgpd/bgp_vty.c1387
-rw-r--r--bgpd/bgp_vty.h106
-rw-r--r--bgpd/bgp_zebra.c155
-rw-r--r--bgpd/bgp_zebra.h7
-rw-r--r--bgpd/bgpd.c193
-rw-r--r--bgpd/bgpd.h175
-rw-r--r--doc/user/bgp.rst175
-rw-r--r--lib/command.h17
-rw-r--r--lib/zclient.c29
-rw-r--r--lib/zclient.h21
-rw-r--r--tests/bgpd/test_mpath.c20
25 files changed, 3546 insertions, 166 deletions
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index f716c4f308..498a871ce7 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -63,6 +63,7 @@ unsigned long conf_bgp_debug_vpn;
unsigned long conf_bgp_debug_flowspec;
unsigned long conf_bgp_debug_labelpool;
unsigned long conf_bgp_debug_pbr;
+unsigned long conf_bgp_debug_graceful_restart;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_neighbor_events;
@@ -80,6 +81,7 @@ unsigned long term_bgp_debug_vpn;
unsigned long term_bgp_debug_flowspec;
unsigned long term_bgp_debug_labelpool;
unsigned long term_bgp_debug_pbr;
+unsigned long term_bgp_debug_graceful_restart;
struct list *bgp_debug_neighbor_events_peers = NULL;
struct list *bgp_debug_keepalive_peers = NULL;
@@ -1644,6 +1646,23 @@ DEFUN (debug_bgp_zebra,
return CMD_SUCCESS;
}
+DEFUN (debug_bgp_graceful_restart,
+ debug_bgp_graceful_restart_cmd,
+ "debug bgp graceful-restart",
+ DEBUG_STR
+ BGP_STR
+ GR_DEBUG)
+{
+ if (vty->node == CONFIG_NODE) {
+ DEBUG_ON(graceful_restart, GRACEFUL_RESTART);
+ } else {
+ TERM_DEBUG_ON(graceful_restart, GRACEFUL_RESTART);
+ vty_out(vty, "BGP Graceful Restart debugging is on\n");
+ }
+ return CMD_SUCCESS;
+}
+
+
DEFUN (debug_bgp_zebra_prefix,
debug_bgp_zebra_prefix_cmd,
"debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
@@ -1702,6 +1721,23 @@ DEFUN (no_debug_bgp_zebra,
return CMD_SUCCESS;
}
+DEFUN (no_debug_bgp_graceful_restart,
+ no_debug_bgp_graceful_restart_cmd,
+ "no debug bgp graceful-restart",
+ DEBUG_STR
+ BGP_STR
+ GR_DEBUG
+ NO_STR)
+{
+ if (vty->node == CONFIG_NODE) {
+ DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+ } else {
+ TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+ vty_out(vty, "BGP Graceful Restart debugging is off\n");
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (no_debug_bgp_zebra_prefix,
no_debug_bgp_zebra_prefix_cmd,
"no debug bgp zebra prefix <A.B.C.D/M|X:X::X:X/M>",
@@ -2039,6 +2075,8 @@ DEFUN (no_debug_bgp,
TERM_DEBUG_OFF(labelpool, LABELPOOL);
TERM_DEBUG_OFF(pbr, PBR);
TERM_DEBUG_OFF(pbr, PBR_ERROR);
+ TERM_DEBUG_OFF(graceful_restart, GRACEFUL_RESTART);
+
vty_out(vty, "All possible debugging has been turned off\n");
return CMD_SUCCESS;
@@ -2094,7 +2132,11 @@ DEFUN_NOSH (show_debugging_bgp,
if (BGP_DEBUG(zebra, ZEBRA))
bgp_debug_list_print(vty, " BGP zebra debugging is on",
- bgp_debug_zebra_prefixes);
+ bgp_debug_zebra_prefixes);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ vty_out(vty,
+ " BGP graceful-restart debugging is on");
if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS))
vty_out(vty, " BGP allow martian next hop debugging is on\n");
@@ -2229,6 +2271,11 @@ static int bgp_config_write_debug(struct vty *vty)
vty_out(vty, "debug bgp pbr error\n");
write++;
}
+
+ if (CONF_BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) {
+ vty_out(vty, "debug bgp graceful-restart\n");
+ write++;
+ }
return write;
}
@@ -2262,6 +2309,9 @@ void bgp_debug_init(void)
install_element(ENABLE_NODE, &debug_bgp_bestpath_prefix_cmd);
install_element(CONFIG_NODE, &debug_bgp_bestpath_prefix_cmd);
+ install_element(ENABLE_NODE, &debug_bgp_graceful_restart_cmd);
+ install_element(CONFIG_NODE, &debug_bgp_graceful_restart_cmd);
+
/* debug bgp updates (in|out) */
install_element(ENABLE_NODE, &debug_bgp_update_direct_cmd);
install_element(CONFIG_NODE, &debug_bgp_update_direct_cmd);
@@ -2327,6 +2377,9 @@ void bgp_debug_init(void)
install_element(ENABLE_NODE, &no_debug_bgp_bestpath_prefix_cmd);
install_element(CONFIG_NODE, &no_debug_bgp_bestpath_prefix_cmd);
+ install_element(ENABLE_NODE, &no_debug_bgp_graceful_restart_cmd);
+ install_element(CONFIG_NODE, &no_debug_bgp_graceful_restart_cmd);
+
install_element(ENABLE_NODE, &debug_bgp_vpn_cmd);
install_element(CONFIG_NODE, &debug_bgp_vpn_cmd);
install_element(ENABLE_NODE, &no_debug_bgp_vpn_cmd);
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index e1072c3df2..1e6482e969 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -76,6 +76,7 @@ extern unsigned long conf_bgp_debug_vpn;
extern unsigned long conf_bgp_debug_flowspec;
extern unsigned long conf_bgp_debug_labelpool;
extern unsigned long conf_bgp_debug_pbr;
+extern unsigned long conf_bgp_debug_graceful_restart;
extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_neighbor_events;
@@ -91,6 +92,7 @@ extern unsigned long term_bgp_debug_vpn;
extern unsigned long term_bgp_debug_flowspec;
extern unsigned long term_bgp_debug_labelpool;
extern unsigned long term_bgp_debug_pbr;
+extern unsigned long term_bgp_debug_graceful_restart;
extern struct list *bgp_debug_neighbor_events_peers;
extern struct list *bgp_debug_keepalive_peers;
@@ -131,6 +133,8 @@ struct bgp_debug_filter {
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
+#define BGP_DEBUG_GRACEFUL_RESTART 0x01
+
#define CONF_DEBUG_ON(a, b) (conf_bgp_debug_ ## a |= (BGP_DEBUG_ ## b))
#define CONF_DEBUG_OFF(a, b) (conf_bgp_debug_ ## a &= ~(BGP_DEBUG_ ## b))
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 3667dae83d..c5b46487a5 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -35,7 +35,7 @@
#include "filter.h"
#include "command.h"
#include "lib_errors.h"
-
+#include "zclient.h"
#include "lib/json.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_attr.h"
@@ -58,7 +58,8 @@
DEFINE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
DEFINE_HOOK(peer_status_changed, (struct peer * peer), (peer))
-
+extern const char *get_afi_safi_str(afi_t afi,
+ safi_t safi, bool for_json);
/* Definition of display strings corresponding to FSM events. This should be
* kept consistent with the events defined in bgpd.h
*/
@@ -250,6 +251,24 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
peer->remote_id = from_peer->remote_id;
peer->last_reset = from_peer->last_reset;
+ peer->peer_gr_present_state = from_peer->peer_gr_present_state;
+ peer->peer_gr_new_status_flag = from_peer->peer_gr_new_status_flag;
+ bgp_peer_gr_flags_update(peer);
+
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+ peer->bgp,
+ peer->bgp->peer);
+
+ if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) {
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+ if (CHECK_FLAG(peer->sflags,
+ PEER_STATUS_NSF_WAIT)) {
+ peer_nsf_stop(peer);
+ }
+ }
+
if (from_peer->hostname != NULL) {
if (peer->hostname) {
XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
@@ -613,6 +632,33 @@ static int bgp_graceful_stale_timer_expire(struct thread *thread)
return 0;
}
+/* Selection deferral timer processing function */
+static int bgp_graceful_deferral_timer_expire(struct thread *thread)
+{
+ struct afi_safi_info *info;
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+
+ info = THREAD_ARG(thread);
+ afi = info->afi;
+ safi = info->safi;
+ bgp = info->bgp;
+
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("afi %d, safi %d : graceful restart deferral timer expired",
+ afi, safi);
+
+ bgp->gr_info[afi][safi].t_select_deferral = NULL;
+
+ bgp->gr_info[afi][safi].eor_required = 0;
+ bgp->gr_info[afi][safi].eor_received = 0;
+ XFREE(MTYPE_TMP, info);
+
+ /* Best path selection */
+ return bgp_best_path_select_defer(bgp, afi, safi);
+}
+
static int bgp_update_delay_applicable(struct bgp *bgp)
{
/* update_delay_over flag should be reset (set to 0) for any new
@@ -1076,6 +1122,10 @@ int bgp_stop(struct peer *peer)
safi_t safi;
char orf_name[BUFSIZ];
int ret = 0;
+ struct bgp *bgp = peer->bgp;
+ struct graceful_restart_info *gr_info = NULL;
+
+ peer->nsf_af_count = 0;
if (peer_dynamic_neighbor(peer)
&& !(CHECK_FLAG(peer->flags, PEER_FLAG_DELETE))) {
@@ -1098,6 +1148,7 @@ int bgp_stop(struct peer *peer)
/* bgp log-neighbor-changes of neighbor Down */
if (bgp_flag_check(peer->bgp, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) {
struct vrf *vrf = vrf_lookup_by_id(peer->bgp->vrf_id);
+
zlog_info(
"%%ADJCHANGE: neighbor %s(%s) in vrf %s Down %s",
peer->host,
@@ -1141,6 +1192,38 @@ int bgp_stop(struct peer *peer)
peer->nsf[afi][safi] = 0;
}
+ /* If peer reset before receiving EOR, decrement EOR count and
+ * cancel the selection deferral timer if there are no
+ * pending EOR messages to be received
+ */
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer)) {
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (peer->afc_nego[afi][safi] &&
+ !CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED)) {
+ gr_info = &bgp->gr_info[afi][safi];
+
+ if (gr_info && (gr_info->eor_required))
+ gr_info->eor_required--;
+
+ if (gr_info && BGP_DEBUG(update,
+ UPDATE_OUT))
+ zlog_debug(
+ "peer %s, EOR_required %d",
+ peer->host,
+ gr_info->eor_required);
+
+ /* There is no pending EOR message */
+ if (gr_info && gr_info->eor_required
+ == 0) {
+ BGP_TIMER_OFF(
+ gr_info->t_select_deferral);
+ gr_info->eor_received = 0;
+ }
+ }
+ }
+ }
+
/* set last reset time */
peer->resettime = peer->uptime = bgp_clock();
@@ -1249,7 +1332,6 @@ int bgp_stop(struct peer *peer)
} else {
bgp_peer_conf_if_to_su_update(peer);
}
-
return ret;
}
@@ -1539,6 +1621,10 @@ static int bgp_reconnect(struct peer *peer)
if (bgp_stop(peer) < 0)
return -1;
+ /* Send graceful restart capabilty */
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+ peer->bgp, peer->bgp->peer);
+
bgp_start(peer);
return 0;
}
@@ -1574,6 +1660,91 @@ static int bgp_fsm_holdtime_expire(struct peer *peer)
return bgp_stop_with_notify(peer, BGP_NOTIFY_HOLD_ERR, 0);
}
+/* Start the selection deferral timer thread for the specified AFI, SAFI */
+static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi,
+ struct graceful_restart_info *gr_info)
+{
+ struct afi_safi_info *thread_info;
+
+ /* If the deferral timer is active, then increment eor count */
+ if (gr_info->t_select_deferral) {
+ gr_info->eor_required++;
+ return 0;
+ }
+
+ /* Start the deferral timer when the first peer enabled for the graceful
+ * restart is established
+ */
+ if (gr_info->eor_required == 0) {
+ thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
+ if (thread_info == NULL) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("%s : Error allocating thread info",
+ __func__);
+ return -1;
+ }
+
+ thread_info->afi = afi;
+ thread_info->safi = safi;
+ thread_info->bgp = bgp;
+
+ thread_add_timer(bm->master,
+ bgp_graceful_deferral_timer_expire,
+ thread_info, bgp->select_defer_time,
+ &gr_info->t_select_deferral);
+ if (gr_info->t_select_deferral == NULL) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("Error starting deferral timer for %s",
+ get_afi_safi_str(afi, safi, false));
+ return -1;
+ }
+ }
+ gr_info->eor_required++;
+ /* Send message to RIB indicating route update pending */
+ if (gr_info->af_enabled[afi][safi] == false) {
+ gr_info->af_enabled[afi][safi] = true;
+ /* Send message to RIB */
+ bgp_zebra_update(afi, safi, bgp->vrf_id,
+ ZEBRA_CLIENT_ROUTE_UPDATE_PENDING);
+ }
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("Started the deferral timer for %s eor_required %d",
+ get_afi_safi_str(afi, safi, false),
+ gr_info->eor_required);
+ return 0;
+}
+
+/* Update the graceful restart information for the specified AFI, SAFI */
+static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi)
+{
+ struct graceful_restart_info *gr_info;
+ struct bgp *bgp = peer->bgp;
+ int ret = 0;
+
+ if ((afi < AFI_IP) || (afi >= AFI_MAX)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("%s : invalid afi %d", __func__, afi);
+ return -1;
+ }
+
+ if ((safi < SAFI_UNICAST) || (safi > SAFI_MPLS_VPN)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("%s : invalid safi %d", __func__, safi);
+ return -1;
+ }
+
+ /* Restarting router */
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
+ BGP_PEER_RESTARTING_MODE(peer)) {
+ /* Check if the forwarding state is preserved */
+ if (bgp_flag_check(bgp, BGP_FLAG_GR_PRESERVE_FWD)) {
+ gr_info = &(bgp->gr_info[afi][safi]);
+ ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info);
+ }
+ }
+ return ret;
+}
+
/**
* Transition to Established state.
*
@@ -1587,6 +1758,7 @@ static int bgp_establish(struct peer *peer)
int nsf_af_count = 0;
int ret = 0;
struct peer *other;
+ int status;
other = peer->doppelganger;
peer = peer_xfer_conn(peer);
@@ -1626,6 +1798,14 @@ static int bgp_establish(struct peer *peer)
/* graceful restart */
UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
+ if (bgp_debug_neighbor_events(peer)) {
+ if (BGP_PEER_RESTARTING_MODE(peer))
+ zlog_debug("peer %s BGP_RESTARTING_MODE",
+ peer->host);
+ else if (BGP_PEER_HELPER_MODE(peer))
+ zlog_debug("peer %s BGP_HELPER_MODE",
+ peer->host);
+ }
for (afi = AFI_IP; afi < AFI_MAX; afi++)
for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
if (peer->afc_nego[afi][safi]
@@ -1645,8 +1825,29 @@ static int bgp_establish(struct peer *peer)
bgp_clear_stale_route(peer, afi, safi);
peer->nsf[afi][safi] = 0;
}
+ /* Update the graceful restart information */
+ if (peer->afc_nego[afi][safi]) {
+ if (!BGP_SELECT_DEFER_DISABLE(peer->bgp)) {
+ status = bgp_update_gr_info(peer, afi,
+ safi);
+ if (status < 0)
+ zlog_err("Error in updating graceful restart for %s",
+ get_afi_safi_str(afi,
+ safi, false));
+ } else {
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(
+ peer) &&
+ BGP_PEER_RESTARTING_MODE(peer)
+ && bgp_flag_check(peer->bgp,
+ BGP_FLAG_GR_PRESERVE_FWD))
+ peer->bgp->gr_info[afi][safi]
+ .eor_required++;
+ }
+ }
}
+ peer->nsf_af_count = nsf_af_count;
+
if (nsf_af_count)
SET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
else {
@@ -2063,3 +2264,498 @@ int bgp_event_update(struct peer *peer, int event)
return ret;
}
+/* BGP GR Code */
+
+int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
+ enum global_mode global_new_state,
+ enum global_mode global_old_state)
+{
+ struct peer *peer = {0};
+ struct listnode *node = {0};
+ struct listnode *nnode = {0};
+ enum peer_mode peer_old_state = PEER_INVALID;
+
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "%s [BGP_GR] Peer: (%s) :",
+ __func__, peer->host);
+
+ peer_old_state = bgp_peer_gr_mode_get(peer);
+
+ if (peer_old_state == PEER_GLOBAL_INHERIT) {
+
+ /*
+ *Reset only these peers and send a
+ *new open message with the change capabilities.
+ *Considering the mode to be "global_new_state" and
+ *do all operation accordingly
+ */
+
+ switch (global_new_state) {
+ case GLOBAL_HELPER:
+ BGP_PEER_GR_HELPER_ENABLE(peer);
+ break;
+ case GLOBAL_GR:
+ BGP_PEER_GR_ENABLE(peer);
+ break;
+ case GLOBAL_DISABLE:
+ BGP_PEER_GR_DISABLE(peer);
+ break;
+ case GLOBAL_INVALID:
+ zlog_debug(
+ "%s [BGP_GR] GLOBAL_INVALID",
+ __func__);
+ return BGP_ERR_GR_OPERATION_FAILED;
+ default:
+ zlog_debug(
+ "%s [BGP_GR] Global unknown ERROR",
+ __func__);
+ return BGP_ERR_GR_OPERATION_FAILED;
+ }
+ }
+ }
+
+ bgp->global_gr_present_state = global_new_state;
+
+ return BGP_GR_SUCCESS;
+}
+
+int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd)
+{
+ enum global_mode global_new_state = GLOBAL_INVALID;
+ enum global_mode global_old_state = GLOBAL_INVALID;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "%s [BGP_GR]START: global_gr_cmd :%s:",
+ __func__, print_global_gr_cmd(global_gr_cmd));
+
+ global_old_state = bgp_global_gr_mode_get(bgp);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] global_old_gr_state :%s:",
+ print_global_gr_mode(global_old_state));
+
+ if (global_old_state != GLOBAL_INVALID) {
+ global_new_state =
+ bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd];
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] global_new_gr_state :%s:",
+ print_global_gr_mode(global_new_state));
+ } else {
+ zlog_err(
+ "%s [BGP_GR] global_old_state == GLOBAL_INVALID",
+ __func__);
+ return BGP_ERR_GR_OPERATION_FAILED;
+ }
+
+ if (global_new_state == GLOBAL_INVALID) {
+ zlog_err(
+ "%s [BGP_GR] global_new_state == GLOBAL_INVALID",
+ __func__);
+ return BGP_ERR_GR_INVALID_CMD;
+ }
+ if (global_new_state == global_old_state) {
+ /* Trace msg */
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "%s [BGP_GR] global_new_state == global_old_state :%s",
+ __func__, print_global_gr_mode(global_new_state));
+ return BGP_GR_NO_OPERATION;
+ }
+
+ return bgp_gr_lookup_n_update_all_peer(bgp,
+ global_new_state,
+ global_old_state);
+}
+
+const char *print_peer_gr_mode(enum peer_mode pr_mode)
+{
+ const char *peer_gr_mode = NULL;
+
+ switch (pr_mode) {
+ case PEER_HELPER:
+ peer_gr_mode = "PEER_HELPER";
+ break;
+ case PEER_GR:
+ peer_gr_mode = "PEER_GR";
+ break;
+ case PEER_DISABLE:
+ peer_gr_mode = "PEER_DISABLE";
+ break;
+ case PEER_INVALID:
+ peer_gr_mode = "PEER_INVALID";
+ break;
+ case PEER_GLOBAL_INHERIT:
+ peer_gr_mode = "PEER_GLOBAL_INHERIT";
+ break;
+ }
+
+ return peer_gr_mode;
+}
+
+const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd)
+{
+ const char *peer_gr_cmd = NULL;
+
+ switch (pr_gr_cmd) {
+ case PEER_GR_CMD:
+ peer_gr_cmd = "PEER_GR_CMD";
+ break;
+ case NO_PEER_GR_CMD:
+ peer_gr_cmd = "NO_PEER_GR_CMD";
+ break;
+ case PEER_DISABLE_CMD:
+ peer_gr_cmd = "PEER_GR_CMD";
+ break;
+ case NO_PEER_DISABLE_CMD:
+ peer_gr_cmd = "NO_PEER_GR_CMD";
+ break;
+ case PEER_HELPER_CMD:
+ peer_gr_cmd = "PEER_HELPER_CMD";
+ break;
+ case NO_PEER_HELPER_CMD:
+ peer_gr_cmd = "NO_PEER_HELPER_CMD";
+ break;
+ }
+
+ return peer_gr_cmd;
+}
+
+const char *print_global_gr_mode(enum global_mode gl_mode)
+{
+ const char *global_gr_mode = NULL;
+
+ switch (gl_mode) {
+ case GLOBAL_HELPER:
+ global_gr_mode = "GLOBAL_HELPER";
+ break;
+ case GLOBAL_GR:
+ global_gr_mode = "GLOBAL_GR";
+ break;
+ case GLOBAL_DISABLE:
+ global_gr_mode = "GLOBAL_DISABLE";
+ break;
+ case GLOBAL_INVALID:
+ global_gr_mode = "GLOBAL_INVALID";
+ break;
+ }
+
+ return global_gr_mode;
+}
+
+const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd)
+{
+ const char *global_gr_cmd = NULL;
+
+ switch (gl_gr_cmd) {
+ case GLOBAL_GR_CMD:
+ global_gr_cmd = "GLOBAL_GR_CMD";
+ break;
+ case NO_GLOBAL_GR_CMD:
+ global_gr_cmd = "NO_GLOBAL_GR_CMD";
+ break;
+ case GLOBAL_DISABLE_CMD:
+ global_gr_cmd = "GLOBAL_DISABLE_CMD";
+ break;
+ case NO_GLOBAL_DISABLE_CMD:
+ global_gr_cmd = "NO_GLOBAL_DISABLE_CMD";
+ break;
+ }
+
+ return global_gr_cmd;
+}
+
+enum global_mode bgp_global_gr_mode_get(struct bgp *bgp)
+{
+ return bgp->global_gr_present_state;
+}
+
+enum peer_mode bgp_peer_gr_mode_get(struct peer *peer)
+{
+ return peer->peer_gr_present_state;
+}
+
+int bgp_neighbor_graceful_restart(struct peer *peer,
+ int peer_gr_cmd)
+{
+ enum peer_mode peer_new_state = PEER_INVALID;
+ enum peer_mode peer_old_state = PEER_INVALID;
+ struct bgp_peer_gr peer_state;
+ int result = BGP_GR_FAILURE;
+
+ /*
+ * fetch peer_old_state from peer structure also
+ * fetch global_old_state from bgp structure,
+ * peer had a back pointer to bgpo struct ;
+ */
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:",
+ __func__, peer->host, print_peer_gr_cmd(peer_gr_cmd));
+
+ peer_old_state = bgp_peer_gr_mode_get(peer);
+
+ if (peer_old_state == PEER_INVALID) {
+ zlog_debug(
+ "[BGP_GR] peer_old_state == Invalid state !");
+ return BGP_ERR_GR_OPERATION_FAILED;
+ }
+
+ peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd];
+ peer_new_state = peer_state.next_state;
+
+ if (peer_new_state == PEER_INVALID) {
+ zlog_debug(
+ "[BGP_GR] Invalid bgp graceful restart command used !");
+ return BGP_ERR_GR_INVALID_CMD;
+ }
+
+ if (peer_new_state != peer_old_state) {
+ result = peer_state.action_fun(peer,
+ peer_old_state,
+ peer_new_state);
+ } else {
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] peer_old_state == peer_new_state !");
+ return BGP_GR_NO_OPERATION;
+ }
+
+ if (result == BGP_GR_SUCCESS) {
+
+ /* Update the mode i.e peer_new_state into the peer structure */
+ peer->peer_gr_present_state = peer_new_state;
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] Succesfully change the state of the peer to : %s : !",
+ print_peer_gr_mode(peer_new_state));
+
+ return BGP_GR_SUCCESS;
+ }
+
+ return result;
+}
+
+unsigned int bgp_peer_gr_action(struct peer *peer,
+ int old_peer_state, int new_peer_state)
+{
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!",
+ __func__, print_peer_gr_mode(old_peer_state),
+ print_peer_gr_mode(new_peer_state));
+
+ int bgp_gr_global_mode = GLOBAL_INVALID;
+ unsigned int ret = BGP_GR_FAILURE;
+
+ if (old_peer_state == new_peer_state) {
+ /* Nothing to do over here as the present and old state is the same */
+ return BGP_GR_NO_OPERATION;
+ }
+ if ((old_peer_state == PEER_INVALID) ||
+ (new_peer_state == PEER_INVALID)) {
+ /* something bad happend , print error message */
+ return BGP_ERR_GR_INVALID_CMD;
+ }
+
+ bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp);
+
+ if ((old_peer_state == PEER_GLOBAL_INHERIT) &&
+ (new_peer_state != PEER_GLOBAL_INHERIT)) {
+
+ /* fetch the Mode running in the Global state machine
+ *from the bgp structure into a variable called
+ *bgp_gr_global_mode
+ */
+
+ /* Here we are checking if the
+ *1. peer_new_state == global_mode == helper_mode
+ *2. peer_new_state == global_mode == GR_mode
+ *3. peer_new_state == global_mode == disabled_mode
+ */
+
+ BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer);
+
+ if (new_peer_state == bgp_gr_global_mode) {
+ /*This is incremental updates i.e no tear down
+ *of the existing session
+ *as the peer is already working in the same mode.
+ */
+ ret = BGP_GR_SUCCESS;
+ } else {
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer state changed from :%s ",
+ print_peer_gr_mode(old_peer_state));
+
+ bgp_peer_move_to_gr_mode(peer, new_peer_state);
+
+ ret = BGP_GR_SUCCESS;
+ }
+ }
+ /* In the case below peer is going into Global inherit mode i.e.
+ * the peer would work as the mode configured at the global level
+ */
+ else if ((new_peer_state == PEER_GLOBAL_INHERIT) &&
+ (old_peer_state != PEER_GLOBAL_INHERIT)) {
+ /* Here in this case it would be destructive
+ * in all the cases except one case when,
+ * Global GR is configured Disabled
+ * and present_peer_state is not disable
+ */
+
+ BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
+
+ if (old_peer_state == bgp_gr_global_mode) {
+
+ /* This is incremental updates
+ *i.e no tear down of the existing session
+ *as the peer is already working in the same mode.
+ */
+ ret = BGP_GR_SUCCESS;
+ } else {
+ /* Destructive always */
+ /* Tear down the old session
+ * and send the new capability
+ * as per the bgp_gr_global_mode
+ */
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] Peer state changed from :%s",
+ print_peer_gr_mode(old_peer_state));
+
+ bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode);
+
+ ret = BGP_GR_SUCCESS;
+ }
+ } else {
+ /*
+ *This else case, it include all the cases except -->
+ *(new_peer_state != Peer_Global) &&
+ *( old_peer_state != Peer_Global )
+ */
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] Peer state changed from :%s",
+ print_peer_gr_mode(old_peer_state));
+
+ bgp_peer_move_to_gr_mode(peer, new_peer_state);
+
+ ret = BGP_GR_SUCCESS;
+ }
+
+ return ret;
+}
+
+inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state)
+
+{
+ int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp);
+
+ switch (new_state) {
+ case PEER_HELPER:
+ BGP_PEER_GR_HELPER_ENABLE(peer);
+ break;
+ case PEER_GR:
+ BGP_PEER_GR_ENABLE(peer);
+ break;
+ case PEER_DISABLE:
+ BGP_PEER_GR_DISABLE(peer);
+ break;
+ case PEER_GLOBAL_INHERIT:
+ BGP_PEER_GR_GLOBAL_INHERIT_SET(peer);
+
+ if (bgp_global_gr_mode == GLOBAL_HELPER) {
+ BGP_PEER_GR_HELPER_ENABLE(peer);
+ } else if (bgp_global_gr_mode == GLOBAL_GR) {
+ BGP_PEER_GR_ENABLE(peer);
+ } else if (bgp_global_gr_mode == GLOBAL_DISABLE) {
+ BGP_PEER_GR_DISABLE(peer);
+ } else {
+ zlog_err(
+ "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!");
+ }
+ break;
+ default:
+ zlog_err("[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!");
+ break;
+ }
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !",
+ new_state);
+}
+
+void bgp_peer_gr_flags_update(struct peer *peer)
+{
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "%s [BGP_GR] called !",
+ __func__);
+ if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
+ SET_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER);
+ else
+ UNSET_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER);
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !",
+ peer->host,
+ (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER) ?
+ "Set" : "UnSet"));
+ if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART))
+ SET_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART);
+ else
+ UNSET_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART);
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !",
+ peer->host,
+ (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART) ?
+ "Set" : "UnSet"));
+ if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT))
+ SET_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT);
+ else
+ UNSET_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT);
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !",
+ peer->host,
+ (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) ?
+ "Set" : "UnSet"));
+
+ if (!CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART) &&
+ !CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER)){
+ zlog_debug(
+ "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!",
+ peer->host);
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+ if (CHECK_FLAG(peer->sflags,
+ PEER_STATUS_NSF_WAIT)) {
+
+ peer_nsf_stop(peer);
+ zlog_debug(
+ "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!",
+ peer->host);
+ }
+ }
+}
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index 6f955c71be..b6abaf3e92 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -56,6 +56,58 @@
#define FSM_PEER_TRANSFERRED 2
#define FSM_PEER_TRANSITIONED 3
+#define BGP_PEER_GR_HELPER_ENABLE(peer) \
+ do { \
+ UNSET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART); \
+ SET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+ } while (0)
+
+#define BGP_PEER_GR_ENABLE(peer)\
+ do { \
+ SET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART); \
+ UNSET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+ } while (0)
+
+#define BGP_PEER_GR_DISABLE(peer)\
+ do { \
+ UNSET_FLAG( \
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART);\
+ UNSET_FLAG(\
+ peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER);\
+ } while (0)
+
+#define BGP_PEER_GR_GLOBAL_INHERIT_SET(peer) \
+ SET_FLAG(peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)
+
+#define BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer) \
+ UNSET_FLAG(peer->peer_gr_new_status_flag, \
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)
+
+#define BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) \
+ (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) && \
+ CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
+
+#define BGP_PEER_RESTARTING_MODE(peer)\
+ (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && \
+ CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV) && \
+ !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV))
+
+#define BGP_PEER_HELPER_MODE(peer)\
+ (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER) && \
+ CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV) && \
+ !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV))
+
/* Prototypes. */
extern void bgp_fsm_event_update(struct peer *peer, int valid);
extern int bgp_event(struct thread *);
@@ -87,6 +139,29 @@ extern void bgp_start_routeadv(struct bgp *);
extern void bgp_adjust_routeadv(struct peer *);
#include "hook.h"
-DECLARE_HOOK(peer_backward_transition, (struct peer * peer), (peer))
+DECLARE_HOOK(peer_backward_transition, (struct peer *peer), (peer))
+DECLARE_HOOK(peer_established, (struct peer *peer), (peer))
+int bgp_gr_update_all(struct bgp *bgp, int global_gr_cmd);
+int bgp_neighbor_graceful_restart(struct peer *peer,
+ int peer_gr_cmd);
+unsigned int bgp_peer_gr_action(struct peer *peer,
+ int old_peer_state, int new_peer_state);
+void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state);
+unsigned int bgp_peer_gr_helper_enable(struct peer *peer);
+unsigned int bgp_peer_gr_enable(struct peer *peer);
+unsigned int bgp_peer_gr_global_inherit(struct peer *peer);
+unsigned int bgp_peer_gr_disable(struct peer *peer);
+enum peer_mode bgp_peer_gr_mode_get(struct peer *peer);
+enum global_mode bgp_global_gr_mode_get(struct bgp *bgp);
+enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer);
+unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer);
+int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp,
+ enum global_mode global_new_state,
+ enum global_mode global_old_state);
+void bgp_peer_gr_flags_update(struct peer *peer);
+const char *print_peer_gr_mode(enum peer_mode pr_mode);
+const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
+const char *print_global_gr_mode(enum global_mode gl_mode);
+const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
#endif /* _QUAGGA_BGP_FSM_H */
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index fed34e5b65..626c36ff05 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -462,7 +462,12 @@ static uint16_t bgp_read(struct peer *peer)
safe_strerror(errno));
if (peer->status == Established) {
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
+ if ((CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART) ||
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER)) &&
+ CHECK_FLAG(peer->sflags,
+ PEER_STATUS_NSF_MODE)) {
peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
} else
@@ -475,10 +480,15 @@ static uint16_t bgp_read(struct peer *peer)
} else if (nbytes == 0) {
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s [Event] BGP connection closed fd %d",
- peer->host, peer->fd);
+ peer->host, peer->fd);
if (peer->status == Established) {
- if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_MODE)) {
+ if ((CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART) ||
+ CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER)) &&
+ CHECK_FLAG(peer->sflags,
+ PEER_STATUS_NSF_MODE)) {
peer->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
SET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT);
} else
diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c
index 9cb3957a86..fab2a584c0 100644
--- a/bgpd/bgp_main.c
+++ b/bgpd/bgp_main.c
@@ -487,6 +487,7 @@ int main(int argc, char **argv)
frr_config_fork();
/* must be called after fork() */
+ bgp_gr_apply_running_config();
bgp_pthreads_run();
frr_run(bm->master);
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 4031d2dfde..d7989af553 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -487,6 +487,22 @@ static int bgp_accept(struct thread *thread)
hash_get(peer->bgp->peerhash, peer, hash_alloc_intern);
peer_xfer_config(peer, peer1);
+ bgp_peer_gr_flags_update(peer);
+
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+ peer->bgp,
+ peer->bgp->peer);
+
+ if (bgp_peer_gr_mode_get(peer) == PEER_DISABLE) {
+
+ UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE);
+
+ if (CHECK_FLAG(peer->sflags,
+ PEER_STATUS_NSF_WAIT)) {
+ peer_nsf_stop(peer);
+ }
+ }
+
UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE);
peer->doppelganger = peer1;
@@ -497,10 +513,9 @@ static int bgp_accept(struct thread *thread)
BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */
SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER);
-
/* Make dummy peer until read Open packet. */
if (peer1->status == Established
- && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) {
+ && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) {
/* If we have an existing established connection with graceful
* restart
* capability announced with one or more address families, then
@@ -508,7 +523,14 @@ static int bgp_accept(struct thread *thread)
* existing established connection and move state to connect.
*/
peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION;
- SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT);
+
+ if (CHECK_FLAG(peer1->flags,
+ PEER_FLAG_GRACEFUL_RESTART) ||
+ CHECK_FLAG(peer1->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER))
+ SET_FLAG(peer1->sflags,
+ PEER_STATUS_NSF_WAIT);
+
bgp_event_update(peer1, TCP_connection_closed);
}
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 23b893c1c8..e743fdda8f 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -462,6 +462,8 @@ static int bgp_capability_restart(struct peer *peer,
restart_flag_time = stream_getw(s);
if (CHECK_FLAG(restart_flag_time, RESTART_R_BIT))
SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV);
+ else
+ UNSET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV);
UNSET_FLAG(restart_flag_time, 0xF000);
peer->v_gr_restart = restart_flag_time;
@@ -828,6 +830,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
int ret;
struct stream *s = BGP_INPUT(peer);
size_t end = stream_get_getp(s) + length;
+ uint16_t restart_flag_time = 0;
assert(STREAM_READABLE(s) >= length);
@@ -1004,6 +1007,12 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
caphdr.length);
stream_set_getp(s, start + caphdr.length);
}
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+ UNSET_FLAG(restart_flag_time, 0xF000);
+ peer->v_gr_restart = restart_flag_time;
+ }
+
}
return 0;
}
@@ -1299,6 +1308,96 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
stream_putc_at(s, capp, cap_len);
}
+static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
+ unsigned long cp)
+{
+ int len;
+ iana_afi_t pkt_afi;
+ afi_t afi;
+ safi_t safi;
+ iana_safi_t pkt_safi;
+ uint32_t restart_time;
+ unsigned long capp = 0;
+ unsigned long rcapp = 0;
+
+ if ((CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART)) ||
+ (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART_HELPER))) {
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Sending helper Capability for Peer :%s :",
+ peer->host);
+
+ SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
+ stream_putc(s, BGP_OPEN_OPT_CAP);
+ capp = stream_get_endp(s); /* Set Capability Len Pointer */
+ stream_putc(s, 0); /* Capability Length */
+ stream_putc(s, CAPABILITY_CODE_RESTART);
+ /* Set Restart Capability Len Pointer */
+ rcapp = stream_get_endp(s);
+ stream_putc(s, 0);
+ restart_time = peer->bgp->restart_time;
+ if (peer->bgp->t_startup) {
+ SET_FLAG(restart_time, RESTART_R_BIT);
+ SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Sending R-Bit for Peer :%s :",
+ peer->host);
+ }
+
+ stream_putw(s, restart_time);
+
+ /* Send address-family specific graceful-restart capability
+ * only when GR config is present
+ */
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) {
+
+ if (bgp_flag_check(peer->bgp,
+ BGP_FLAG_GR_PRESERVE_FWD) &&
+ BGP_DEBUG(graceful_restart,
+ GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] F bit Set");
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (peer->afc[afi][safi]) {
+ if (BGP_DEBUG(graceful_restart,
+ GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:",
+ afi, safi);
+
+ /* Convert AFI, SAFI to values for
+ * packet.
+ */
+ bgp_map_afi_safi_int2iana(afi,
+ safi, &pkt_afi,
+ &pkt_safi);
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
+ if (bgp_flag_check(peer->bgp,
+ BGP_FLAG_GR_PRESERVE_FWD)) {
+ stream_putc(s, RESTART_F_BIT);
+
+ } else {
+ stream_putc(s, 0);
+ }
+ }
+ }
+ }
+ /* Total Graceful restart capability Len. */
+ len = stream_get_endp(s) - rcapp - 1;
+ stream_putc_at(s, rcapp, len);
+
+ /* Total Capability Len. */
+ len = stream_get_endp(s) - capp - 1;
+ stream_putc_at(s, capp, len);
+ }
+}
+
/* Fill in capability open option to the packet. */
void bgp_open_capability(struct stream *s, struct peer *peer)
{
@@ -1309,7 +1408,6 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
safi_t safi;
iana_safi_t pkt_safi;
as_t local_as;
- uint32_t restart_time;
uint8_t afi_safi_count = 0;
int adv_addpath_tx = 0;
@@ -1502,50 +1600,7 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
cmd_domainname_get());
}
- /* Sending base graceful-restart capability irrespective of the config
- */
- SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
- stream_putc(s, BGP_OPEN_OPT_CAP);
- capp = stream_get_endp(s); /* Set Capability Len Pointer */
- stream_putc(s, 0); /* Capability Length */
- stream_putc(s, CAPABILITY_CODE_RESTART);
- rcapp = stream_get_endp(s); /* Set Restart Capability Len Pointer */
- stream_putc(s, 0);
- restart_time = peer->bgp->restart_time;
- if (peer->bgp->t_startup) {
- SET_FLAG(restart_time, RESTART_R_BIT);
- SET_FLAG(peer->cap, PEER_CAP_RESTART_BIT_ADV);
- }
- stream_putw(s, restart_time);
-
- /* Send address-family specific graceful-restart capability only when GR
- config
- is present */
- if (bgp_flag_check(peer->bgp, BGP_FLAG_GRACEFUL_RESTART)) {
- FOREACH_AFI_SAFI (afi, safi) {
- if (peer->afc[afi][safi]) {
- /* Convert AFI, SAFI to values for
- * packet. */
- bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
- &pkt_safi);
- stream_putw(s, pkt_afi);
- stream_putc(s, pkt_safi);
- if (bgp_flag_check(peer->bgp,
- BGP_FLAG_GR_PRESERVE_FWD))
- stream_putc(s, RESTART_F_BIT);
- else
- stream_putc(s, 0);
- }
- }
- }
-
- /* Total Graceful restart capability Len. */
- len = stream_get_endp(s) - rcapp - 1;
- stream_putc_at(s, rcapp, len);
-
- /* Total Capability Len. */
- len = stream_get_endp(s) - capp - 1;
- stream_putc_at(s, capp, len);
+ bgp_peer_send_gr_capability(s, peer, cp);
/* Total Opt Parm Len. */
len = stream_get_endp(s) - cp - 1;
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index b7e9af002b..e77194a624 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -439,28 +439,41 @@ int bgp_generate_updgrp_packets(struct thread *thread)
*/
if (!next_pkt || !next_pkt->buffer) {
if (CHECK_FLAG(peer->cap,
- PEER_CAP_RESTART_RCV)) {
+ PEER_CAP_RESTART_RCV)) {
if (!(PAF_SUBGRP(paf))->t_coalesce
- && peer->afc_nego[afi][safi]
- && peer->synctime
- && !CHECK_FLAG(
- peer->af_sflags[afi]
- [safi],
- PEER_STATUS_EOR_SEND)) {
- SET_FLAG(peer->af_sflags[afi]
- [safi],
- PEER_STATUS_EOR_SEND);
-
- if ((s = bgp_update_packet_eor(
- peer, afi,
- safi))) {
- bgp_packet_add(peer, s);
+ && peer->afc_nego[afi][safi]
+ && peer->synctime
+ && !CHECK_FLAG(
+ peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND)) {
+ /* If EOR is disabled,
+ * the message is not sent
+ */
+ if (BGP_SEND_EOR(peer->bgp,
+ afi, safi)) {
+ SET_FLAG(
+ peer->af_sflags
+ [afi][safi],
+ PEER_STATUS_EOR_SEND);
+
+ /* Update EOR
+ * send time
+ */
+ peer->eor_stime
+ [afi][safi] =
+ monotime(NULL);
+
+ BGP_UPDATE_EOR_PKT(
+ peer, afi,
+ safi, s);
}
}
}
continue;
}
+ /* Update packet send time */
+ peer->pkt_stime[afi][safi] = monotime(NULL);
/* Found a packet template to send, overwrite
* packet with appropriate attributes from peer
@@ -723,11 +736,14 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
if (first) {
snprintf(c, sizeof(c), " %02x",
data[i]);
+
strlcat(bgp_notify.data, c,
bgp_notify.length);
+
} else {
first = 1;
snprintf(c, sizeof(c), "%02x", data[i]);
+
strlcpy(bgp_notify.data, c,
bgp_notify.length);
}
@@ -755,6 +771,11 @@ void bgp_notify_send_with_data(struct peer *peer, uint8_t code,
/* Add packet to peer's output queue */
stream_fifo_push(peer->obuf, s);
+ bgp_peer_gr_flags_update(peer);
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+ peer->bgp,
+ peer->bgp->peer);
+
bgp_write_notify(peer);
}
@@ -1404,6 +1425,7 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
bgp_size_t attribute_len;
bgp_size_t update_len;
bgp_size_t withdraw_len;
+ bool restart = false;
enum NLRI_TYPES {
NLRI_UPDATE,
@@ -1626,6 +1648,12 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
|| (attr_parse_ret == BGP_ATTR_PARSE_EOR)) {
afi_t afi = 0;
safi_t safi;
+ struct graceful_restart_info *gr_info;
+
+ /* Restarting router */
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
+ BGP_PEER_RESTARTING_MODE(peer))
+ restart = true;
/* Non-MP IPv4/Unicast is a completely emtpy UPDATE - already
* checked
@@ -1652,6 +1680,32 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size)
SET_FLAG(peer->af_sflags[afi][safi],
PEER_STATUS_EOR_RECEIVED);
bgp_update_explicit_eors(peer);
+ /* Update graceful restart information */
+ gr_info = &(peer->bgp->gr_info[afi][safi]);
+ if (restart)
+ gr_info->eor_received++;
+ /* If EOR received from all peers and selection
+ * deferral timer is running, cancel the timer
+ * and invoke the best path calculation
+ */
+ if (gr_info->eor_required ==
+ gr_info->eor_received) {
+ if (bgp_debug_neighbor_events(
+ peer))
+ zlog_debug("%s %d, %s %d",
+ "EOR REQ",
+ gr_info->eor_required,
+ "EOR RCV",
+ gr_info->eor_received);
+ BGP_TIMER_OFF(
+ gr_info->t_select_deferral);
+ gr_info->eor_required = 0;
+ gr_info->eor_received = 0;
+ /* Best path selection */
+ if (bgp_best_path_select_defer(
+ peer->bgp, afi, safi) < 0)
+ return BGP_Stop;
+ }
}
/* NSF delete stale route */
@@ -1723,14 +1777,18 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
if (first) {
snprintf(c, sizeof(c), " %02x",
stream_getc(peer->curr));
+
strlcat(bgp_notify.data, c,
- bgp_notify.length);
+ bgp_notify.length * 3);
+
} else {
first = 1;
snprintf(c, sizeof(c), "%02x",
stream_getc(peer->curr));
+
strlcpy(bgp_notify.data, c,
- bgp_notify.length);
+ bgp_notify.length * 3);
+
}
bgp_notify.raw_data = (uint8_t *)peer->notify.data;
}
@@ -1756,6 +1814,11 @@ static int bgp_notify_receive(struct peer *peer, bgp_size_t size)
&& bgp_notify.subcode == BGP_NOTIFY_OPEN_UNSUP_PARAM)
UNSET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+ bgp_peer_gr_flags_update(peer);
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+ peer->bgp,
+ peer->bgp->peer);
+
return Receive_NOTIFICATION_message;
}
@@ -2374,3 +2437,14 @@ int bgp_process_packet(struct thread *thread)
return 0;
}
+
+/* Send EOR when routes are processed by selection deferral timer */
+void bgp_send_delayed_eor(struct bgp *bgp)
+{
+ struct peer *peer;
+ struct listnode *node, *nnode;
+
+ /* EOR message sent in bgp_write_proceed_actions */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer))
+ bgp_write_proceed_actions(peer);
+}
diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h
index 49e401790f..0242abab26 100644
--- a/bgpd/bgp_packet.h
+++ b/bgpd/bgp_packet.h
@@ -48,6 +48,14 @@ DECLARE_HOOK(bgp_packet_send,
#define ORF_COMMON_PART_PERMIT 0x00
#define ORF_COMMON_PART_DENY 0x20
+#define BGP_UPDATE_EOR_PKT(_peer, _afi, _safi, _s) \
+ do { \
+ _s = bgp_update_packet_eor(_peer, _afi, _safi); \
+ if (_s) { \
+ bgp_packet_add(_peer, _s); \
+ } \
+ } while (0)
+
/* Packet send and receive function prototypes. */
extern void bgp_keepalive_send(struct peer *);
extern void bgp_open_send(struct peer *);
@@ -73,4 +81,5 @@ extern int bgp_packet_set_size(struct stream *s);
extern int bgp_generate_updgrp_packets(struct thread *);
extern int bgp_process_packet(struct thread *);
+extern void bgp_send_delayed_eor(struct bgp *bgp);
#endif /* _QUAGGA_BGP_PACKET_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 5f4486b800..f7ace6aede 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -40,7 +40,7 @@
#include "memory.h"
#include "lib/json.h"
#include "lib_errors.h"
-
+#include "zclient.h"
#include "bgpd/bgpd.h"
#include "bgpd/bgp_table.h"
#include "bgpd/bgp_route.h"
@@ -89,7 +89,8 @@
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
extern const char *bgp_origin_long_str[];
-
+const char *get_afi_safi_str(afi_t afi,
+ safi_t safi, bool for_json);
/* PMSI strings. */
#define PMSI_TNLTYPE_STR_NO_INFO "No info"
#define PMSI_TNLTYPE_STR_DEFAULT PMSI_TNLTYPE_STR_NO_INFO
@@ -295,6 +296,85 @@ struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path)
return path;
}
+/* This function sets flag BGP_NODE_SELECT_DEFER based on condition */
+static int bgp_node_set_defer_flag(struct bgp_node *rn, bool delete)
+{
+ struct peer *peer;
+ struct bgp_path_info *old_pi, *nextpi;
+ bool set_flag = 0;
+ struct bgp *bgp = NULL;
+ struct bgp_table *table = NULL;
+ afi_t afi = 0;
+ safi_t safi = 0;
+ char buf[PREFIX2STR_BUFFER];
+
+ /* If the flag BGP_NODE_SELECT_DEFER is set and new path is added
+ * then the route selection is deferred
+ */
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER) && (!delete))
+ return 0;
+
+ if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED)) {
+ if (BGP_DEBUG(update, UPDATE_OUT)) {
+ prefix2str(&rn->p, buf, PREFIX2STR_BUFFER);
+ zlog_debug("Route %s is in workqueue and being processed, not deferred.",
+ buf);
+ }
+ return 0;
+ }
+
+ table = bgp_node_table(rn);
+ if (table) {
+ bgp = table->bgp;
+ afi = table->afi;
+ safi = table->safi;
+ }
+
+ for (old_pi = bgp_node_get_bgp_path_info(rn);
+ (old_pi != NULL) && (nextpi = old_pi->next, 1); old_pi = nextpi) {
+ if (CHECK_FLAG(old_pi->flags, BGP_PATH_SELECTED))
+ continue;
+
+ /* Route selection is deferred if there is a stale path which
+ * which indicates peer is in restart mode
+ */
+ if (CHECK_FLAG(old_pi->flags, BGP_PATH_STALE) &&
+ (old_pi->sub_type == BGP_ROUTE_NORMAL)) {
+ set_flag = 1;
+ } else {
+ /* If the peer is graceful restart capable and peer is
+ * restarting mode, set the flag BGP_NODE_SELECT_DEFER
+ */
+ peer = old_pi->peer;
+ if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) &&
+ BGP_PEER_RESTARTING_MODE(peer) &&
+ (old_pi && old_pi->sub_type == BGP_ROUTE_NORMAL)) {
+ set_flag = 1;
+ }
+ }
+ if (set_flag)
+ break;
+ }
+
+ /* Set the flag BGP_NODE_SELECT_DEFER if route selection deferral timer
+ * is active
+ */
+ if (set_flag && table) {
+ if (bgp && (bgp->gr_info[afi][safi].t_select_deferral)) {
+ SET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+ prefix2str(&rn->p, buf, PREFIX2STR_BUFFER);
+ if (rn->rt_node == NULL)
+ rn->rt_node = listnode_add(
+ bgp->gr_info[afi][safi].route_list, rn);
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("DEFER route %s, rn %p, node %p",
+ buf, rn, rn->rt_node);
+ return 0;
+ }
+ }
+ return -1;
+}
+
void bgp_path_info_add(struct bgp_node *rn, struct bgp_path_info *pi)
{
struct bgp_path_info *top;
@@ -310,6 +390,7 @@ void bgp_path_info_add(struct bgp_node *rn, struct bgp_path_info *pi)
bgp_path_info_lock(pi);
bgp_lock_node(rn);
peer_lock(pi->peer); /* bgp_path_info peer reference */
+ bgp_node_set_defer_flag(rn, false);
}
/* Do the actual removal of info from RIB, for use by bgp_process
@@ -1973,6 +2054,30 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_path_info *pi,
return 1;
}
+static int bgp_route_select_timer_expire(struct thread *thread)
+{
+ struct afi_safi_info *info;
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+
+ info = THREAD_ARG(thread);
+ afi = info->afi;
+ safi = info->safi;
+ bgp = info->bgp;
+
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("afi %d, safi %d : route select timer expired",
+ afi, safi);
+
+ bgp->gr_info[afi][safi].t_route_select = NULL;
+
+ XFREE(MTYPE_TMP, info);
+
+ /* Best path selection */
+ return bgp_best_path_select_defer(bgp, afi, safi);
+}
+
void bgp_best_selection(struct bgp *bgp, struct bgp_node *rn,
struct bgp_maxpaths_cfg *mpath_cfg,
struct bgp_path_info_pair *result, afi_t afi,
@@ -2376,6 +2481,15 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
afi2str(afi), safi2str(safi));
}
+ /* The best path calculation for the route is deferred if
+ * BGP_NODE_SELECT_DEFER is set
+ */
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("SELECT_DEFER falg set for route %p", rn);
+ return;
+ }
+
/* Best path selection. */
bgp_best_selection(bgp, rn, &bgp->maxpaths[afi][safi], &old_and_new,
afi, safi);
@@ -2603,6 +2717,78 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_node *rn,
return;
}
+/* Process the routes with the flag BGP_NODE_SELECT_DEFER set */
+int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi)
+{
+ struct bgp_node *rn;
+ int cnt = 0;
+ struct afi_safi_info *thread_info;
+ struct listnode *node = NULL, *nnode = NULL;
+
+ if (bgp->gr_info[afi][safi].t_route_select)
+ BGP_TIMER_OFF(bgp->gr_info[afi][safi].t_route_select);
+
+ if (BGP_DEBUG(update, UPDATE_OUT)) {
+ zlog_debug("%s: processing route for %s : cnt %d",
+ __func__, get_afi_safi_str(afi, safi, false),
+ listcount(bgp->gr_info[afi][safi].route_list));
+ }
+
+ /* Process the route list */
+ node = listhead(bgp->gr_info[afi][safi].route_list);
+ while (node) {
+ rn = listgetdata(node);
+ nnode = node->next;
+ list_delete_node(bgp->gr_info[afi][safi].route_list, node);
+ rn->rt_node = NULL;
+
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+ UNSET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+ bgp_process_main_one(bgp, rn, afi, safi);
+ cnt++;
+ if (cnt >= BGP_MAX_BEST_ROUTE_SELECT)
+ break;
+ }
+ node = nnode;
+ }
+
+ /* Send EOR message when all routes are processed */
+ if (list_isempty(bgp->gr_info[afi][safi].route_list)) {
+ bgp_send_delayed_eor(bgp);
+ /* Send route processing complete message to RIB */
+ bgp_zebra_update(afi, safi, bgp->vrf_id,
+ ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE);
+ return 0;
+ }
+
+ thread_info = XMALLOC(MTYPE_TMP, sizeof(struct afi_safi_info));
+ if (thread_info == NULL) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("%s : error allocating thread info",
+ __func__);
+ return -1;
+ }
+
+ thread_info->afi = afi;
+ thread_info->safi = safi;
+ thread_info->bgp = bgp;
+
+ /* If there are more routes to be processed, start the
+ * selection timer
+ */
+ thread_add_timer(bm->master, bgp_route_select_timer_expire, thread_info,
+ BGP_ROUTE_SELECT_DELAY,
+ &bgp->gr_info[afi][safi].t_route_select);
+ if (bgp->gr_info[afi][safi].t_route_select == NULL) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("%s : error starting selection thread for %s",
+ __func__, get_afi_safi_str(afi,
+ safi, false));
+ return -1;
+ }
+ return 0;
+}
+
static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
{
struct bgp_process_queue *pqnode = data;
@@ -2681,6 +2867,16 @@ void bgp_process(struct bgp *bgp, struct bgp_node *rn, afi_t afi, safi_t safi)
if (CHECK_FLAG(rn->flags, BGP_NODE_PROCESS_SCHEDULED))
return;
+ /* If the flag BGP_NODE_SELECT_DEFER is set, do not add route to
+ * the workqueue
+ */
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+ if (BGP_DEBUG(update, UPDATE_OUT))
+ zlog_debug("BGP_NODE_SELECT_DEFER set for route %p",
+ rn);
+ return;
+ }
+
if (wq == NULL)
return;
@@ -2844,13 +3040,41 @@ int bgp_maximum_prefix_overflow(struct peer *peer, afi_t afi, safi_t safi,
void bgp_rib_remove(struct bgp_node *rn, struct bgp_path_info *pi,
struct peer *peer, afi_t afi, safi_t safi)
{
+
+ struct bgp *bgp = NULL;
+ bool delete_route = false;
+
bgp_aggregate_decrement(peer->bgp, &rn->p, pi, afi, safi);
- if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY))
+ if (!CHECK_FLAG(pi->flags, BGP_PATH_HISTORY)) {
bgp_path_info_delete(rn, pi); /* keep historical info */
- hook_call(bgp_process, peer->bgp, afi, safi, rn, peer, true);
+ /* If the selected path is removed, reset BGP_NODE_SELECT_DEFER
+ * flag
+ */
+ if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
+ delete_route = true;
+ else
+ if (bgp_node_set_defer_flag(rn, true) < 0)
+ delete_route = true;
+ if (delete_route) {
+ if (CHECK_FLAG(rn->flags, BGP_NODE_SELECT_DEFER)) {
+ UNSET_FLAG(rn->flags, BGP_NODE_SELECT_DEFER);
+ bgp = pi->peer->bgp;
+ if ((rn->rt_node) &&
+ (bgp->gr_info[afi][safi]
+ .route_list)) {
+ list_delete_node(
+ bgp->gr_info[afi][safi]
+ .route_list,
+ rn->rt_node);
+ rn->rt_node = NULL;
+ }
+ }
+ }
+ }
+ hook_call(bgp_process, peer->bgp, afi, safi, rn, peer, true);
bgp_process(peer->bgp, rn, afi, safi);
}
@@ -3302,6 +3526,7 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
if (CHECK_FLAG(pi->flags, BGP_PATH_STALE)) {
bgp_path_info_unset_flag(
rn, pi, BGP_PATH_STALE);
+ bgp_node_set_defer_flag(rn, false);
bgp_process(bgp, rn, afi, safi);
}
}
@@ -3337,8 +3562,10 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id,
}
/* graceful restart STALE flag unset. */
- if (CHECK_FLAG(pi->flags, BGP_PATH_STALE))
+ if (CHECK_FLAG(pi->flags, BGP_PATH_STALE)) {
bgp_path_info_unset_flag(rn, pi, BGP_PATH_STALE);
+ bgp_node_set_defer_flag(rn, false);
+ }
/* The attribute is changed. */
bgp_path_info_set_flag(rn, pi, BGP_PATH_ATTR_CHANGED);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index b9f3f3f762..e335c39fb1 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -635,4 +635,5 @@ extern int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi,
struct bgp_table *table, struct prefix_rd *prd,
enum bgp_show_type type, void *output_arg,
bool use_json);
+extern int bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi);
#endif /* _QUAGGA_BGP_ROUTE_H */
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index b75246b172..4868686305 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -127,6 +127,43 @@ struct bgp_table *bgp_table_init(struct bgp *bgp, afi_t afi, safi_t safi)
return rt;
}
+/* Delete the route node from the selection deferral route list */
+void bgp_delete_listnode(struct bgp_node *node)
+{
+ struct route_node *rn = NULL;
+ struct bgp_table *table = NULL;
+ struct bgp *bgp = NULL;
+ afi_t afi;
+ safi_t safi;
+
+ /* If the route to be deleted is selection pending, update the
+ * route node in gr_info
+ */
+ if (CHECK_FLAG(node->flags, BGP_NODE_SELECT_DEFER)) {
+ table = bgp_node_table(node);
+
+ if (table) {
+ bgp = table->bgp;
+ afi = table->afi;
+ safi = table->safi;
+ } else
+ return;
+
+ rn = bgp_node_to_rnode(node);
+
+ if (bgp && rn && rn->lock == 1) {
+ /* Delete the route from the selection pending list */
+ if ((node->rt_node) &&
+ (bgp->gr_info[afi][safi].route_list)) {
+ list_delete_node(
+ bgp->gr_info[afi][safi].route_list,
+ node->rt_node);
+ node->rt_node = NULL;
+ }
+ }
+ }
+}
+
static struct bgp_node *
bgp_route_next_until_maxlen(struct bgp_node *node, const struct bgp_node *limit,
const uint8_t maxlen)
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index b3542e7848..69cca9eee4 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -28,6 +28,8 @@
#include "bgpd.h"
#include "bgp_advertise.h"
+extern void bgp_delete_listnode(struct bgp_node *node);
+
struct bgp_table {
/* table belongs to this instance */
struct bgp *bgp;
@@ -95,7 +97,9 @@ struct bgp_node {
#define BGP_NODE_USER_CLEAR (1 << 1)
#define BGP_NODE_LABEL_CHANGED (1 << 2)
#define BGP_NODE_REGISTERED_FOR_LABEL (1 << 3)
-
+#define BGP_NODE_SELECT_DEFER (1 << 4)
+ /* list node pointer */
+ struct listnode *rt_node;
struct bgp_addpath_node_data tx_addpath;
enum bgp_path_selection_reason reason;
@@ -162,6 +166,7 @@ static inline struct bgp_node *bgp_node_parent_nolock(struct bgp_node *node)
*/
static inline void bgp_unlock_node(struct bgp_node *node)
{
+ bgp_delete_listnode(node);
route_unlock_node(bgp_node_to_rnode(node));
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 9dc6549d9c..eff5b3b7bc 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -105,9 +105,39 @@ DEFINE_HOOK(bgp_inst_config_write,
(struct bgp *bgp, struct vty *vty),
(bgp, vty))
+#define GR_NO_OPER "The Graceful Restart No Operation was executed as cmd same as previous one."
+#define GR_INVALID "The Graceful Restart command used is not valid at this moment."
static struct peer_group *listen_range_exists(struct bgp *bgp,
struct prefix *range, int exact);
+/* Show BGP peer's information. */
+enum show_type {
+ show_all,
+ show_peer,
+ show_ipv4_all,
+ show_ipv6_all,
+ show_ipv4_peer,
+ show_ipv6_peer
+};
+
+static struct peer_group *listen_range_exists(
+ struct bgp *bgp,
+ struct prefix *range,
+ int exact);
+
+static void bgp_show_global_graceful_restart_mode_vty(
+ struct vty *vty,
+ struct bgp *bgp,
+ bool use_json,
+ json_object *json);
+
+static int bgp_show_neighbor_graceful_restart_afi_all(
+ struct vty *vty,
+ enum show_type type,
+ const char *ip_str,
+ afi_t afi,
+ bool use_json);
+
static enum node_type bgp_node_type(afi_t afi, safi_t safi)
{
switch (afi) {
@@ -690,7 +720,16 @@ int bgp_vty_return(struct vty *vty, int ret)
str = "Operation not allowed on a directly connected neighbor";
break;
case BGP_ERR_PEER_SAFI_CONFLICT:
- str = "Cannot activate peer for both 'ipv4 unicast' and 'ipv4 labeled-unicast'";
+ str = GR_INVALID;
+ break;
+ case BGP_ERR_GR_INVALID_CMD:
+ str = "The Graceful Restart command used is not valid at this moment.";
+ break;
+ case BGP_ERR_GR_OPERATION_FAILED:
+ str = "The Graceful Restart Operation failed due to an err.";
+ break;
+ case BGP_GR_NO_OPERATION:
+ str = GR_NO_OPER;
break;
}
if (str) {
@@ -785,7 +824,8 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
int ret = 0;
bool found = false;
struct peer *peer;
- struct listnode *node, *nnode;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
/* Clear all neighbors. */
/*
@@ -795,11 +835,27 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
*/
if (sort == clear_all) {
for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+ bgp_peer_gr_flags_update(peer);
+
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART))
+ gr_router_detected = true;
+
ret = bgp_peer_clear(peer, afi, safi, nnode,
stype);
if (ret < 0)
bgp_clear_vty_error(vty, peer, afi, safi, ret);
+
+ }
+
+ if (gr_router_detected &&
+ bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+ bgp_zebra_send_capabilities(bgp, false);
+ } else if (!gr_router_detected &&
+ bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+ bgp_zebra_send_capabilities(bgp, true);
}
/* This is to apply read-only mode on this clear. */
@@ -836,6 +892,9 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
}
}
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
ret = bgp_peer_clear(peer, afi, safi, NULL, stype);
/* if afi/safi not defined for this peer, let caller know */
@@ -881,6 +940,12 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (peer->sort == BGP_PEER_IBGP)
continue;
+ bgp_peer_gr_flags_update(peer);
+
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART))
+ gr_router_detected = true;
+
ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
if (ret < 0)
@@ -889,6 +954,14 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
found = true;
}
+ if (gr_router_detected &&
+ bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+ bgp_zebra_send_capabilities(bgp, false);
+ } else if (!gr_router_detected &&
+ bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+ bgp_zebra_send_capabilities(bgp, true);
+ }
+
if (!found)
vty_out(vty,
"%%BGP: No external %s peer is configured\n",
@@ -905,6 +978,12 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
if (peer->as != as)
continue;
+ bgp_peer_gr_flags_update(peer);
+
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART))
+ gr_router_detected = true;
+
ret = bgp_peer_clear(peer, afi, safi, nnode, stype);
if (ret < 0)
@@ -913,6 +992,14 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
found = true;
}
+ if (gr_router_detected &&
+ bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+ bgp_zebra_send_capabilities(bgp, false);
+ } else if (!gr_router_detected &&
+ bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+ bgp_zebra_send_capabilities(bgp, true);
+ }
+
if (!found)
vty_out(vty,
"%%BGP: No %s peer is configured with AS %s\n",
@@ -2093,37 +2180,68 @@ DEFUN (no_bgp_deterministic_med,
return CMD_SUCCESS;
}
-/* "bgp graceful-restart" configuration. */
+/* "bgp graceful-restart mode" configuration. */
DEFUN (bgp_graceful_restart,
- bgp_graceful_restart_cmd,
- "bgp graceful-restart",
- "BGP specific commands\n"
- "Graceful restart capability parameters\n")
+ bgp_graceful_restart_cmd,
+ "bgp graceful-restart",
+ "BGP specific commands\n"
+ GR_CMD
+ )
{
+ int ret = BGP_GR_FAILURE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : START ");
+
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp_flag_set(bgp, BGP_FLAG_GRACEFUL_RESTART);
- return CMD_SUCCESS;
+
+ ret = bgp_gr_update_all(bgp, GLOBAL_GR_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] bgp_graceful_restart_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+ return bgp_vty_return(vty, ret);
}
DEFUN (no_bgp_graceful_restart,
- no_bgp_graceful_restart_cmd,
- "no bgp graceful-restart",
- NO_STR
- "BGP specific commands\n"
- "Graceful restart capability parameters\n")
+ no_bgp_graceful_restart_cmd,
+ "no bgp graceful-restart",
+ NO_STR
+ "BGP specific commands\n"
+ NO_GR_CMD
+ )
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp_flag_unset(bgp, BGP_FLAG_GRACEFUL_RESTART);
- return CMD_SUCCESS;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : START ");
+
+ int ret = BGP_GR_FAILURE;
+
+ ret = bgp_gr_update_all(bgp, NO_GLOBAL_GR_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] no_bgp_graceful_restart_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+
+ return bgp_vty_return(vty, ret);
}
DEFUN (bgp_graceful_restart_stalepath_time,
- bgp_graceful_restart_stalepath_time_cmd,
- "bgp graceful-restart stalepath-time (1-4095)",
- "BGP specific commands\n"
- "Graceful restart capability parameters\n"
- "Set the max time to hold onto restarting peer's stale paths\n"
- "Delay value (seconds)\n")
+ bgp_graceful_restart_stalepath_time_cmd,
+ "bgp graceful-restart stalepath-time (1-4095)",
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the max time to hold onto restarting peer's stale paths\n"
+ "Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_number = 3;
@@ -2135,12 +2253,12 @@ DEFUN (bgp_graceful_restart_stalepath_time,
}
DEFUN (bgp_graceful_restart_restart_time,
- bgp_graceful_restart_restart_time_cmd,
- "bgp graceful-restart restart-time (1-4095)",
- "BGP specific commands\n"
- "Graceful restart capability parameters\n"
- "Set the time to wait to delete stale routes before a BGP open message is received\n"
- "Delay value (seconds)\n")
+ bgp_graceful_restart_restart_time_cmd,
+ "bgp graceful-restart restart-time (1-4095)",
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the time to wait to delete stale routes before a BGP open message is received\n"
+ "Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
int idx_number = 3;
@@ -2151,14 +2269,36 @@ DEFUN (bgp_graceful_restart_restart_time,
return CMD_SUCCESS;
}
-DEFUN (no_bgp_graceful_restart_stalepath_time,
- no_bgp_graceful_restart_stalepath_time_cmd,
- "no bgp graceful-restart stalepath-time [(1-4095)]",
- NO_STR
+DEFUN (bgp_graceful_restart_select_defer_time,
+ bgp_graceful_restart_select_defer_time_cmd,
+ "bgp graceful-restart select-defer-time (0-3600)",
"BGP specific commands\n"
"Graceful restart capability parameters\n"
- "Set the max time to hold onto restarting peer's stale paths\n"
- "Delay value (seconds)\n")
+ "Set the time to defer the BGP route selection after restart\n"
+ "Delay value (seconds, 0 - disable)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int idx_number = 3;
+ uint32_t defer_time;
+
+ defer_time = strtoul(argv[idx_number]->arg, NULL, 10);
+ bgp->select_defer_time = defer_time;
+ if (defer_time == 0)
+ bgp_flag_set(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+ else
+ bgp_flag_unset(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_stalepath_time,
+ no_bgp_graceful_restart_stalepath_time_cmd,
+ "no bgp graceful-restart stalepath-time [(1-4095)]",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the max time to hold onto restarting peer's stale paths\n"
+ "Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
@@ -2167,26 +2307,43 @@ DEFUN (no_bgp_graceful_restart_stalepath_time,
}
DEFUN (no_bgp_graceful_restart_restart_time,
- no_bgp_graceful_restart_restart_time_cmd,
- "no bgp graceful-restart restart-time [(1-4095)]",
+ no_bgp_graceful_restart_restart_time_cmd,
+ "no bgp graceful-restart restart-time [(1-4095)]",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Set the time to wait to delete stale routes before a BGP open message is received\n"
+ "Delay value (seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_select_defer_time,
+ no_bgp_graceful_restart_select_defer_time_cmd,
+ "no bgp graceful-restart select-defer-time [(0-3600)]",
NO_STR
"BGP specific commands\n"
"Graceful restart capability parameters\n"
- "Set the time to wait to delete stale routes before a BGP open message is received\n"
+ "Set the time to defer the BGP route selection after restart\n"
"Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
+ bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME;
+ bgp_flag_unset(bgp, BGP_FLAG_SELECT_DEFER_DISABLE);
+
return CMD_SUCCESS;
}
DEFUN (bgp_graceful_restart_preserve_fw,
- bgp_graceful_restart_preserve_fw_cmd,
- "bgp graceful-restart preserve-fw-state",
- "BGP specific commands\n"
- "Graceful restart capability parameters\n"
- "Sets F-bit indication that fib is preserved while doing Graceful Restart\n")
+ bgp_graceful_restart_preserve_fw_cmd,
+ "bgp graceful-restart preserve-fw-state",
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Sets F-bit indication that fib is preserved while doing Graceful Restart\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
bgp_flag_set(bgp, BGP_FLAG_GR_PRESERVE_FWD);
@@ -2194,15 +2351,366 @@ DEFUN (bgp_graceful_restart_preserve_fw,
}
DEFUN (no_bgp_graceful_restart_preserve_fw,
- no_bgp_graceful_restart_preserve_fw_cmd,
- "no bgp graceful-restart preserve-fw-state",
+ no_bgp_graceful_restart_preserve_fw_cmd,
+ "no bgp graceful-restart preserve-fw-state",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart capability parameters\n"
+ "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp_flag_unset(bgp, BGP_FLAG_GR_PRESERVE_FWD);
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_graceful_restart_disable,
+ bgp_graceful_restart_disable_cmd,
+ "bgp graceful-restart-disable",
+ "BGP specific commands\n"
+ GR_DISABLE)
+{
+ int ret = BGP_GR_FAILURE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_graceful_restart_disable_cmd : START ");
+
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ ret = bgp_gr_update_all(bgp, GLOBAL_DISABLE_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_graceful_restart_disable_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_graceful_restart_disable,
+ no_bgp_graceful_restart_disable_cmd,
+ "no bgp graceful-restart-disable",
+ NO_STR
+ "BGP specific commands\n"
+ NO_GR_DISABLE
+ )
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_graceful_restart_disable_cmd : START ");
+
+ int ret = BGP_GR_FAILURE;
+
+ ret = bgp_gr_update_all(bgp, NO_GLOBAL_DISABLE_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp,
+ bgp->peer, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_graceful_restart_disable_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset all peers to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_set,
+ bgp_neighbor_graceful_restart_set_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ GR_NEIGHBOR_CMD
+ )
+{
+ int idx_peer = 1;
+ struct peer *peer;
+ int ret = BGP_GR_FAILURE;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : START ");
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = bgp_neighbor_graceful_restart(peer, PEER_GR_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart,
+ no_bgp_neighbor_graceful_restart_set_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ NO_GR_NEIGHBOR_CMD
+ )
+{
+ int idx_peer = 2;
+ int ret = BGP_GR_FAILURE;
+ struct peer *peer;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : START ");
+
+ ret = bgp_neighbor_graceful_restart(peer, NO_PEER_GR_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_helper_set,
+ bgp_neighbor_graceful_restart_helper_set_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-helper",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ GR_NEIGHBOR_HELPER_CMD
+ )
+{
+ int idx_peer = 1;
+ struct peer *peer;
+ int ret = BGP_GR_FAILURE;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : START ");
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+
+ ret = bgp_neighbor_graceful_restart(peer, PEER_HELPER_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_helper_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart_helper,
+ no_bgp_neighbor_graceful_restart_helper_set_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-helper",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ NO_GR_NEIGHBOR_HELPER_CMD
+ )
+{
+ int idx_peer = 2;
+ int ret = BGP_GR_FAILURE;
+ struct peer *peer;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : START ");
+
+ ret = bgp_neighbor_graceful_restart(peer,
+ NO_PEER_HELPER_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_helper_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (bgp_neighbor_graceful_restart_disable_set,
+ bgp_neighbor_graceful_restart_disable_set_cmd,
+ "neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-disable",
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ GR_NEIGHBOR_DISABLE_CMD
+ )
+{
+ int idx_peer = 1;
+ struct peer *peer;
+ int ret = BGP_GR_FAILURE;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] bgp_neighbor_graceful_restart_disable_set_cmd : START ");
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ ret = bgp_neighbor_graceful_restart(peer,
+ PEER_DISABLE_CMD);
+
+ if (peer->bgp->t_startup)
+ bgp_peer_gr_flags_update(peer);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR]bgp_neighbor_graceful_restart_disable_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN (no_bgp_neighbor_graceful_restart_disable,
+ no_bgp_neighbor_graceful_restart_disable_set_cmd,
+ "no neighbor <A.B.C.D|X:X::X:X|WORD> graceful-restart-disable",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ NO_GR_NEIGHBOR_DISABLE_CMD
+ )
+{
+ int idx_peer = 2;
+ int ret = BGP_GR_FAILURE;
+ struct peer *peer;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
+
+ peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : START ");
+
+ ret = bgp_neighbor_graceful_restart(peer, NO_PEER_DISABLE_CMD);
+
+ VTY_BGP_GR_ROUTER_DETECT(bgp, peer, peer->bgp->peer);
+ VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(peer->bgp, ret);
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug(
+ "[BGP_GR] no_bgp_neighbor_graceful_restart_disable_set_cmd : END ");
+ vty_out(vty,
+ "Graceful restart configuration changed, reset this peer to take effect\n");
+
+ return bgp_vty_return(vty, ret);
+}
+
+DEFUN_HIDDEN (bgp_graceful_restart_disable_eor,
+ bgp_graceful_restart_disable_eor_cmd,
+ "bgp graceful-restart disable-eor",
+ "BGP specific commands\n"
+ "Graceful restart configuration parameters\n"
+ "Disable EOR Check\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp_flag_set(bgp, BGP_FLAG_GR_DISABLE_EOR);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN_HIDDEN (no_bgp_graceful_restart_disable_eor,
+ no_bgp_graceful_restart_disable_eor_cmd,
+ "no bgp graceful-restart disable-eor",
+ NO_STR
+ "BGP specific commands\n"
+ "Graceful restart configuration parameters\n"
+ "Disable EOR Check\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ bgp_flag_unset(bgp, BGP_FLAG_GR_DISABLE_EOR);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (bgp_graceful_restart_rib_stale_time,
+ bgp_graceful_restart_rib_stale_time_cmd,
+ "bgp graceful-restart rib-stale-time (1-3600)",
+ "BGP specific commands\n"
+ "Graceful restart configuration parameters\n"
+ "Specify the stale route removal timer in rib\n"
+ "Delay value (seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int idx_number = 3;
+ uint32_t stale_time;
+
+ stale_time = strtoul(argv[idx_number]->arg, NULL, 10);
+ bgp->rib_stale_time = stale_time;
+ /* Send the stale timer update message to RIB */
+ if (bgp_zebra_stale_timer_update(bgp))
+ return CMD_WARNING;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_bgp_graceful_restart_rib_stale_time,
+ no_bgp_graceful_restart_rib_stale_time_cmd,
+ "no bgp graceful-restart rib-stale-time [(1-3600)]",
NO_STR
"BGP specific commands\n"
- "Graceful restart capability parameters\n"
- "Unsets F-bit indication that fib is preserved while doing Graceful Restart\n")
+ "Graceful restart configuration parameters\n"
+ "Specify the stale route removal timer in rib\n"
+ "Delay value (seconds)\n")
{
VTY_DECLVAR_CONTEXT(bgp, bgp);
- bgp_flag_unset(bgp, BGP_FLAG_GR_PRESERVE_FWD);
+
+ bgp->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME;
+ /* Send the stale timer update message to RIB */
+ if (bgp_zebra_stale_timer_update(bgp))
+ return CMD_WARNING;
+
return CMD_SUCCESS;
}
@@ -8882,8 +9390,6 @@ const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json)
return get_afi_safi_vty_str(afi, safi);
}
-/* Show BGP peer's information. */
-enum show_type { show_all, show_peer, show_ipv4_all, show_ipv6_all, show_ipv4_peer, show_ipv6_peer };
static void bgp_show_peer_afi_orf_cap(struct vty *vty, struct peer *p,
afi_t afi, safi_t safi,
@@ -8948,6 +9454,429 @@ 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)
+{
+ bool rbit_status = 0;
+
+ if (!use_json)
+ vty_out(vty, "\n R bit : ");
+
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) &&
+ (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) &&
+ (p->status == Established)) {
+
+ if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_BIT_RCV))
+ rbit_status = 1;
+ else
+ rbit_status = 0;
+ }
+
+ if (rbit_status) {
+ if (use_json)
+ json_object_boolean_true_add(
+ json, "rBit");
+ else
+ vty_out(vty, "True\n");
+ } else {
+ if (use_json)
+ json_object_boolean_false_add(
+ json, "rBit");
+ else
+ vty_out(vty, "False\n");
+ }
+}
+
+static void bgp_show_neighbor_graceful_restart_remote_mode(
+ struct vty *vty,
+ struct peer *peer,
+ bool use_json,
+ json_object *json)
+{
+ const char *mode = "NotApplicable";
+
+ if (!use_json)
+ vty_out(vty, "\n Remote GR Mode : ");
+
+ if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) &&
+ (peer->status == Established)) {
+
+ if ((peer->nsf_af_count == 0) &&
+ !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+
+ mode = "Disable";
+
+ } else if (peer->nsf_af_count == 0 &&
+ CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+
+ mode = "Helper";
+
+ } else if (peer->nsf_af_count != 0 &&
+ CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) {
+
+ mode = "Restart";
+
+ }
+ }
+
+ if (use_json) {
+ json_object_string_add(json,
+ "remoteGrMode", mode);
+ } else
+ vty_out(vty, mode, "\n");
+}
+
+static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty,
+ struct peer *p,
+ bool use_json,
+ json_object *json)
+{
+ const char *mode = "Invalid";
+
+ if (!use_json)
+ vty_out(vty, " Local GR Mode : ");
+
+ if (bgp_peer_gr_mode_get(p) == PEER_HELPER)
+ mode = "Helper";
+ else if (bgp_peer_gr_mode_get(p) == PEER_GR)
+ mode = "Restart";
+ else if (bgp_peer_gr_mode_get(p) == PEER_DISABLE)
+ mode = "Disable";
+ else if (bgp_peer_gr_mode_get(p) == PEER_GLOBAL_INHERIT) {
+ if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_HELPER)
+ mode = "Helper*";
+ else if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_GR)
+ mode = "Restart*";
+ else if (bgp_global_gr_mode_get(p->bgp) == GLOBAL_DISABLE)
+ mode = "Disable*";
+ else
+ mode = "Invalid*";
+ }
+
+ if (use_json) {
+ json_object_string_add(json,
+ "localGrMode", mode);
+ } else {
+ vty_out(vty, mode, "\n");
+ }
+}
+
+static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi(
+ struct vty *vty, struct peer *peer,
+ bool use_json, json_object *json)
+{
+ afi_t afi;
+ safi_t safi;
+ json_object *json_afi_safi = NULL;
+ json_object *json_timer = NULL;
+ json_object *json_endofrib_status = NULL;
+ bool eor_flag = false;
+
+ for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+ for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) {
+ if (peer->afc[afi][safi]
+ && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
+ && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)
+ ) {
+ if (use_json) {
+ json_afi_safi =
+ json_object_new_object();
+ json_endofrib_status =
+ json_object_new_object();
+ json_timer =
+ json_object_new_object();
+ }
+
+ if (peer->eor_stime[afi][safi] >=
+ peer->pkt_stime[afi][safi])
+ eor_flag = true;
+ else
+ eor_flag = false;
+
+ if (!use_json) {
+ vty_out(vty, " %s :\n",
+ get_afi_safi_str(afi, safi, false));
+
+ vty_out(vty,
+ " F bit : ");
+ } else
+ get_afi_safi_str(afi, safi, true);
+
+ if (peer->nsf[afi][safi]
+ && CHECK_FLAG(
+ peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_PRESERVE_RCV)) {
+
+ if (use_json) {
+ json_object_boolean_true_add(
+ json_afi_safi, "fBit");
+ } else {
+ vty_out(vty,
+ "True\n");
+ }
+
+ } else {
+
+ if (use_json) {
+ json_object_boolean_false_add(
+ json_afi_safi, "fBit");
+ } else {
+ vty_out(vty,
+ "False\n");
+ }
+
+ }
+
+ if (!use_json)
+ vty_out(vty,
+ " End-of-RIB Received : ");
+
+ if (CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED)) {
+
+ if (use_json) {
+ json_object_boolean_true_add(
+ json_endofrib_status,
+ "endOfRibRecv");
+ } else {
+ vty_out(vty, "Yes\n");
+ }
+
+ } else {
+ if (use_json) {
+ json_object_boolean_false_add(
+ json_endofrib_status,
+ "endOfRibRecv");
+ } else {
+ vty_out(vty, "No\n");
+ }
+ }
+
+ if (!use_json)
+ vty_out(vty,
+ " End-of-RIB Send : ");
+
+ if (CHECK_FLAG(peer->af_sflags[afi][safi],
+ PEER_STATUS_EOR_SEND)) {
+ if (use_json) {
+ json_object_boolean_true_add(
+ json_endofrib_status,
+ "endOfRibSend");
+
+ PRINT_EOR_JSON(eor_flag);
+ } else {
+ vty_out(vty, "Yes\n");
+ vty_out(vty,
+ " EoRSentAfterUpdate : ");
+
+ PRINT_EOR(eor_flag);
+ }
+ } else {
+ if (use_json) {
+ json_object_boolean_false_add(
+ json_endofrib_status,
+ "endOfRibSend");
+ json_object_boolean_false_add(
+ json_endofrib_status,
+ "endOfRibSentAfterUpdate");
+ } else {
+ vty_out(vty, "No\n");
+ vty_out(vty,
+ " EoRSentAfterUpdate : ");
+ vty_out(vty, "No\n");
+ }
+ }
+
+ if (use_json) {
+
+ json_object_int_add(json_timer,
+ "stalePathTimer",
+ peer->bgp->stalepath_time);
+
+ if (peer->t_gr_stale != NULL) {
+
+ json_object_int_add(
+ json_timer,
+ "stalePathTimerRemaining",
+ thread_timer_remain_second(
+ peer->t_gr_stale));
+ }
+
+ /* Display Configured Selection
+ * Deferral only when when
+ * Gr mode is enabled.
+ */
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART)) {
+
+ json_object_int_add(
+ json_timer,
+ "selectionDeferralTimer",
+ peer->bgp->stalepath_time);
+ }
+
+ if (peer->bgp->gr_info[afi][safi]
+ .t_select_deferral != NULL) {
+
+ json_object_int_add(
+ json_timer,
+ "selectionDeferralTimerRemaining",
+ thread_timer_remain_second(
+ peer->bgp
+ ->gr_info[afi][safi]
+ .t_select_deferral));
+ }
+
+ } else {
+
+ vty_out(vty, " Timers:\n");
+
+ vty_out(vty, "%*s", 6, "");
+ vty_out(vty,
+ "Configured Stale Path Time(sec)%*s: %u\n",
+ 8, "",
+ peer->bgp->stalepath_time);
+
+ if (peer->t_gr_stale != NULL) {
+ vty_out(vty, "%*s", 6, "");
+ vty_out(vty,
+ "Stale Path Remaining(sec)%*s: %ld\n",
+ 14, "",
+ thread_timer_remain_second(
+ peer->t_gr_stale));
+ }
+ /* Display Configured Selection
+ * Deferral only when when
+ * Gr mode is enabled.
+ */
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART)) {
+ vty_out(vty, "%*s", 6, "");
+ vty_out(vty,
+ "Configured Selection Deferral Time(sec): %u\n",
+ peer->bgp->select_defer_time);
+ }
+
+ if (peer->bgp
+ ->gr_info[afi][safi]
+ .t_select_deferral != NULL) {
+
+ vty_out(vty, "%*s", 6, "");
+ vty_out(vty,
+ "Selection Deferral Time Remaining(sec) : %ld\n",
+ thread_timer_remain_second(
+ peer->bgp
+ ->gr_info[afi][safi]
+ .t_select_deferral));
+ }
+
+ }
+ if (use_json) {
+ json_object_object_add(json_afi_safi,
+ "endOfRibStatus",
+ json_endofrib_status);
+ json_object_object_add(json_afi_safi,
+ "timers",
+ json_timer);
+ json_object_object_add(json,
+ get_afi_safi_str(afi, safi, true),
+ json_afi_safi);
+ }
+ }
+ }
+ }
+}
+
+static void bgp_show_neighbor_graceful_restart_time(struct vty *vty,
+ struct peer *p,
+ bool use_json,
+ json_object *json)
+{
+ if (use_json) {
+ json_object *json_timer = NULL;
+
+ json_timer = json_object_new_object();
+
+ json_object_int_add(json_timer,
+ "configuredRestartTimer",
+ p->bgp->restart_time);
+
+ json_object_int_add(json_timer,
+ "receivedRestartTimer",
+ p->v_gr_restart);
+
+ if (p->t_gr_restart != NULL) {
+ json_object_int_add(json_timer,
+ "restartTimerRemaining",
+ thread_timer_remain_second(
+ p->t_gr_restart)
+ );
+ }
+
+ json_object_object_add(json, "timers", json_timer);
+ } else {
+
+ vty_out(vty, " Timers :\n");
+ vty_out(vty,
+ " Configured Restart Time(sec) : %u\n",
+ p->bgp->restart_time);
+
+ vty_out(vty,
+ " Received Restart Time(sec) : %u\n",
+ p->v_gr_restart);
+ if (p->t_gr_restart != NULL) {
+ vty_out(vty,
+ " Restart Time Remaining(sec) : %ld\n",
+ thread_timer_remain_second(
+ p->t_gr_restart));
+ }
+ }
+}
+
+static void bgp_show_peer_gr_status(struct vty *vty, struct peer *p,
+ bool use_json,
+ json_object *json)
+{
+ char buf[SU_ADDRSTRLEN] = {0};
+ char dn_flag[2] = {0};
+ char neighborAddr[INET6_ADDRSTRLEN] = {0};
+
+ if (!p->conf_if && peer_dynamic_neighbor(p))
+ dn_flag[0] = '*';
+
+ if (p->conf_if) {
+ if (use_json)
+ json_object_string_add(json, "neighborAddr",
+ BGP_PEER_SU_UNSPEC(p)
+ ? "none"
+ : sockunion2str(&p->su, buf,
+ SU_ADDRSTRLEN));
+ else
+ vty_out(vty, "BGP neighbor on %s: %s\n",
+ p->conf_if,
+ BGP_PEER_SU_UNSPEC(p)
+ ? "none"
+ : sockunion2str(&p->su, buf,
+ SU_ADDRSTRLEN));
+ } else {
+ sprintf(neighborAddr, "%s%s", dn_flag, p->host);
+
+ if (use_json)
+ json_object_string_add(
+ json, "neighborAddr",
+ neighborAddr);
+ else
+ vty_out(vty, "BGP neighbor is %s\n",
+ neighborAddr);
+ }
+
+ /* more gr info in new format */
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json);
+}
+
static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
safi_t safi, bool use_json,
json_object *json_neigh)
@@ -9262,7 +10191,9 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
"prefixAllowedRestartIntervalMsecs",
p->pmax_restart[afi][safi] * 60000);
}
- json_object_object_add(json_neigh, get_afi_safi_str(afi, safi, true),
+ json_object_object_add(json_neigh,
+ get_afi_safi_str(afi,
+ safi, true),
json_addr);
} else {
@@ -10701,14 +11632,12 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
vty_out(vty, "none");
vty_out(vty, "\n");
}
- }
+ } /* Gracefull Restart */
}
}
}
/* graceful restart information */
- if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || p->t_gr_restart
- || p->t_gr_stale) {
json_object *json_grace = NULL;
json_object *json_grace_send = NULL;
json_object *json_grace_recv = NULL;
@@ -10720,10 +11649,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
json_grace_send = json_object_new_object();
json_grace_recv = json_object_new_object();
- if (p->status == Established) {
+ if ((p->status == Established) &&
+ CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(p->af_sflags[afi][safi],
- PEER_STATUS_EOR_SEND)) {
+ PEER_STATUS_EOR_SEND)) {
json_object_boolean_true_add(
json_grace_send,
get_afi_safi_str(afi,
@@ -10734,8 +11664,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
}
FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(
- p->af_sflags[afi][safi],
- PEER_STATUS_EOR_RECEIVED)) {
+ p->af_sflags[afi][safi],
+ PEER_STATUS_EOR_RECEIVED)) {
json_object_boolean_true_add(
json_grace_recv,
get_afi_safi_str(afi,
@@ -10745,11 +11675,13 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
}
}
}
+ json_object_object_add(json_grace,
+ "endOfRibSend",
+ json_grace_send);
+ json_object_object_add(json_grace,
+ "endOfRibRecv",
+ json_grace_recv);
- json_object_object_add(json_grace, "endOfRibSend",
- json_grace_send);
- json_object_object_add(json_grace, "endOfRibRecv",
- json_grace_recv);
if (p->t_gr_restart)
json_object_int_add(json_grace,
@@ -10765,12 +11697,16 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
thread_timer_remain_second(
p->t_gr_stale)
* 1000);
-
+ /* more gr info in new format */
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json,
+ json_grace);
json_object_object_add(
json_neigh, "gracefulRestartInfo", json_grace);
} else {
- vty_out(vty, " Graceful restart information:\n");
- if (p->status == Established) {
+ vty_out(vty, " Graceful restart informations:\n");
+ if ((p->status == Established) &&
+ CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) {
+
vty_out(vty, " End-of-RIB send: ");
FOREACH_AFI_SAFI (afi, safi) {
if (CHECK_FLAG(p->af_sflags[afi][safi],
@@ -10779,8 +11715,8 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
eor_send_af_count ? ", "
: "",
get_afi_safi_str(afi,
- safi,
- false));
+ safi,
+ false));
eor_send_af_count++;
}
}
@@ -10814,8 +11750,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
" The remaining time of stalepath timer is %ld\n",
thread_timer_remain_second(
p->t_gr_stale));
+
+ /* more gr info in new format */
+ BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, NULL);
}
- }
+
if (use_json) {
json_object *json_stat = NULL;
json_stat = json_object_new_object();
@@ -11229,6 +12168,84 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
}
}
+static int bgp_show_neighbor_graceful_restart(struct vty *vty,
+ struct bgp *bgp,
+ enum show_type type,
+ union sockunion *su,
+ const char *conf_if, afi_t afi,
+ bool use_json, json_object *json)
+{
+ struct listnode *node, *nnode;
+ struct peer *peer;
+ int find = 0;
+ safi_t safi = SAFI_UNICAST;
+ json_object *json_neighbor = NULL;
+
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE))
+ continue;
+
+ if ((peer->afc[afi][safi]) == 0)
+ continue;
+
+ if (use_json)
+ json_neighbor = json_object_new_object();
+
+ if (type == show_all) {
+ bgp_show_peer_gr_status(vty, peer, use_json,
+ json_neighbor);
+
+ if (use_json)
+ json_object_object_add(json,
+ peer->host, json_neighbor);
+
+ } else if (type == show_peer) {
+ if (conf_if) {
+ if ((peer->conf_if
+ && !strcmp(peer->conf_if, conf_if))
+ || (peer->hostname
+ && !strcmp(peer->hostname, conf_if))) {
+ find = 1;
+ bgp_show_peer_gr_status(vty,
+ peer, use_json,
+ json_neighbor);
+ }
+ } else {
+ if (sockunion_same(&peer->su, su)) {
+ find = 1;
+ bgp_show_peer_gr_status(vty,
+ peer, use_json,
+ json_neighbor);
+ }
+ }
+ if (use_json && find) {
+ json_object_object_add(json,
+ peer->host, json_neighbor);
+ }
+ }
+
+ if (find)
+ break;
+ }
+
+ if (type == show_peer && !find) {
+ if (use_json)
+ json_object_boolean_true_add(json,
+ "bgpNoSuchNeighbor");
+ else
+ vty_out(vty, "%% No such neighbor\n");
+ }
+ if (use_json) {
+ vty_out(vty, "%s\n", json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ } else {
+ vty_out(vty, "\n");
+ }
+
+ return CMD_SUCCESS;
+}
+
static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
enum show_type type, union sockunion *su,
const char *conf_if, bool use_json,
@@ -11334,6 +12351,46 @@ static int bgp_show_neighbor(struct vty *vty, struct bgp *bgp,
return CMD_SUCCESS;
}
+static void bgp_show_neighbor_graceful_restart_vty(struct vty *vty,
+ enum show_type type, const char *ip_str,
+ afi_t afi, bool use_json)
+{
+
+ int ret;
+ struct bgp *bgp;
+ union sockunion su;
+ json_object *json = NULL;
+
+ bgp = bgp_get_default();
+
+ if (bgp) {
+
+ if (!use_json) {
+ bgp_show_global_graceful_restart_mode_vty(vty, bgp,
+ use_json, NULL);
+ }
+
+ json = json_object_new_object();
+ if (ip_str) {
+ ret = str2sockunion(ip_str, &su);
+ if (ret < 0)
+ bgp_show_neighbor_graceful_restart(vty,
+ bgp, type, NULL, ip_str,
+ afi, use_json, json);
+ else
+ bgp_show_neighbor_graceful_restart(vty,
+ bgp, type, &su, NULL,
+ afi, use_json, json);
+ } else {
+ bgp_show_neighbor_graceful_restart(vty, bgp,
+ type, NULL, NULL, afi,
+ use_json, json);
+ }
+ json_object_free(json);
+ }
+
+}
+
static void bgp_show_all_instances_neighbors_vty(struct vty *vty,
enum show_type type,
const char *ip_str,
@@ -11471,6 +12528,51 @@ static int bgp_show_neighbor_vty(struct vty *vty, const char *name,
return CMD_SUCCESS;
}
+
+
+/* "show [ip] bgp neighbors graceful-restart" commands. */
+DEFUN (show_ip_bgp_neighbors_gracrful_restart,
+ show_ip_bgp_neighbors_graceful_restart_cmd,
+ "show bgp [<ipv4|ipv6>] neighbors [<A.B.C.D|X:X::X:X|WORD>] graceful-restart [json]",
+ SHOW_STR
+ BGP_STR
+ IP_STR
+ IPV6_STR
+ NEIGHBOR_STR
+ "Neighbor to display information about\n"
+ "Neighbor to display information about\n"
+ "Neighbor on BGP configured interface\n"
+ GR_SHOW
+ JSON_STR)
+{
+ char *sh_arg = NULL;
+ enum show_type sh_type;
+ int idx = 0;
+ afi_t afi = AFI_MAX;
+ bool uj = use_json(argc, argv);
+
+ if (!argv_find_and_parse_afi(argv, argc, &idx, &afi))
+ afi = AFI_MAX;
+
+ idx++;
+
+ if (argv_find(argv, argc, "A.B.C.D", &idx)
+ || argv_find(argv, argc, "X:X::X:X", &idx)
+ || argv_find(argv, argc, "WORD", &idx)) {
+ sh_type = show_peer;
+ sh_arg = argv[idx]->arg;
+ } else
+ sh_type = show_all;
+
+ if (!argv_find(argv, argc, "graceful-restart", &idx))
+ return CMD_SUCCESS;
+
+
+ return bgp_show_neighbor_graceful_restart_afi_all(vty,
+ sh_type, sh_arg,
+ afi, uj);
+}
+
/* "show [ip] bgp neighbors" commands. */
DEFUN (show_ip_bgp_neighbors,
show_ip_bgp_neighbors_cmd,
@@ -11609,7 +12711,72 @@ DEFUN (show_ip_bgp_lcommunity_info,
return CMD_SUCCESS;
}
+/* Graceful Restart */
+
+static void bgp_show_global_graceful_restart_mode_vty(struct vty *vty,
+ struct bgp *bgp,
+ bool use_json,
+ json_object *json)
+{
+
+ vty_out(vty, "\n%s", SHOW_GR_HEADER);
+
+ int bgp_global_gr_mode = bgp_global_gr_mode_get(bgp);
+
+ switch (bgp_global_gr_mode) {
+
+ case GLOBAL_HELPER:
+ vty_out(vty,
+ "Global BGP GR Mode : Helper\n");
+ break;
+
+ case GLOBAL_GR:
+ vty_out(vty,
+ "Global BGP GR Mode : Restart\n");
+ break;
+
+ case GLOBAL_DISABLE:
+ vty_out(vty,
+ "Global BGP GR Mode : Disable\n");
+ break;
+
+ case GLOBAL_INVALID:
+ default:
+ vty_out(vty,
+ "Global BGP GR Mode Invalid\n");
+ break;
+ }
+ vty_out(vty, "\n");
+}
+
+static int bgp_show_neighbor_graceful_restart_afi_all(struct vty *vty,
+ enum show_type type,
+ const char *ip_str,
+ afi_t afi,
+ bool use_json)
+{
+ if ((afi == AFI_MAX) && (ip_str == NULL)) {
+ afi = AFI_IP;
+
+ while ((afi != AFI_L2VPN) && (afi < AFI_MAX)) {
+
+ bgp_show_neighbor_graceful_restart_vty(vty,
+ type, ip_str,
+ afi, use_json);
+ afi++;
+ }
+ } else if (afi != AFI_MAX) {
+ bgp_show_neighbor_graceful_restart_vty(vty,
+ type, ip_str,
+ afi, use_json);
+ } else {
+ return CMD_ERR_INCOMPLETE;
+ }
+
+ return CMD_SUCCESS;
+}
+/* Graceful Restart */
DEFUN (show_ip_bgp_attr_info,
show_ip_bgp_attr_info_cmd,
@@ -13437,6 +14604,27 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
if (peer->as_path_loop_detection)
vty_out(vty, " neighbor %s sender-as-path-loop-detection\n",
addr);
+
+ if (!CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) {
+
+ if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) {
+ vty_out(vty,
+ " neighbor %s graceful-restart-helper\n", addr);
+ } else if (CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) {
+ vty_out(vty,
+ " neighbor %s graceful-restart\n", addr);
+ } else if ((!(CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_HELPER))
+ && !(CHECK_FLAG(peer->peer_gr_new_status_flag,
+ PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)))) {
+ vty_out(vty,
+ " neighbor %s graceful-restart-disable\n",
+ addr);
+ }
+ }
}
/* BGP peer configuration display function. */
@@ -13963,12 +15151,22 @@ int bgp_config_write(struct vty *vty)
vty_out(vty,
" bgp graceful-restart stalepath-time %u\n",
bgp->stalepath_time);
+
if (bgp->restart_time != BGP_DEFAULT_RESTART_TIME)
vty_out(vty, " bgp graceful-restart restart-time %u\n",
bgp->restart_time);
- if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_RESTART))
+
+ if (bgp->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME)
+ vty_out(vty,
+ " bgp graceful-restart select-defer-time %u\n",
+ bgp->select_defer_time);
+
+ if (bgp_global_gr_mode_get(bgp) == GLOBAL_GR)
vty_out(vty, " bgp graceful-restart\n");
+ if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE)
+ vty_out(vty, " bgp graceful-restart-disable\n");
+
/* BGP graceful-shutdown */
if (bgp_flag_check(bgp, BGP_FLAG_GRACEFUL_SHUTDOWN))
vty_out(vty, " bgp graceful-shutdown\n");
@@ -13978,6 +15176,12 @@ int bgp_config_write(struct vty *vty)
vty_out(vty,
" bgp graceful-restart preserve-fw-state\n");
+ /* Stale timer for RIB */
+ if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME)
+ vty_out(vty,
+ " bgp graceful-restart rib-stale-time %u\n",
+ bgp->rib_stale_time);
+
/* BGP bestpath method. */
if (bgp_flag_check(bgp, BGP_FLAG_ASPATH_IGNORE))
vty_out(vty, " bgp bestpath as-path ignore\n");
@@ -14346,17 +15550,51 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_deterministic_med_cmd);
install_element(BGP_NODE, &no_bgp_deterministic_med_cmd);
- /* "bgp graceful-restart" commands */
- install_element(BGP_NODE, &bgp_graceful_restart_cmd);
- install_element(BGP_NODE, &no_bgp_graceful_restart_cmd);
+ /* "bgp graceful-restart" command */
+ install_element(BGP_NODE,
+ &bgp_graceful_restart_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_graceful_restart_cmd);
+
+ /* "bgp graceful-restart-disable" command */
+ install_element(BGP_NODE,
+ &bgp_graceful_restart_disable_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_graceful_restart_disable_cmd);
+
+ /* "neighbor a:b:c:d graceful-restart" command */
+ install_element(BGP_NODE,
+ &bgp_neighbor_graceful_restart_set_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_neighbor_graceful_restart_set_cmd);
+
+ /* "neighbor a:b:c:d graceful-restart-disable" command */
+ install_element(BGP_NODE,
+ &bgp_neighbor_graceful_restart_disable_set_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_neighbor_graceful_restart_disable_set_cmd);
+
+ /* "neighbor a:b:c:d graceful-restart-helper" command */
+ install_element(BGP_NODE,
+ &bgp_neighbor_graceful_restart_helper_set_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_neighbor_graceful_restart_helper_set_cmd);
+
install_element(BGP_NODE, &bgp_graceful_restart_stalepath_time_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_stalepath_time_cmd);
install_element(BGP_NODE, &bgp_graceful_restart_restart_time_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_restart_time_cmd);
-
+ install_element(BGP_NODE, &bgp_graceful_restart_select_defer_time_cmd);
+ install_element(BGP_NODE,
+ &no_bgp_graceful_restart_select_defer_time_cmd);
install_element(BGP_NODE, &bgp_graceful_restart_preserve_fw_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_preserve_fw_cmd);
+ install_element(BGP_NODE, &bgp_graceful_restart_disable_eor_cmd);
+ install_element(BGP_NODE, &no_bgp_graceful_restart_disable_eor_cmd);
+ install_element(BGP_NODE, &bgp_graceful_restart_rib_stale_time_cmd);
+ install_element(BGP_NODE, &no_bgp_graceful_restart_rib_stale_time_cmd);
+
/* "bgp graceful-shutdown" commands */
install_element(BGP_NODE, &bgp_graceful_shutdown_cmd);
install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd);
@@ -15351,6 +16589,9 @@ void bgp_vty_init(void)
/* "show [ip] bgp neighbors" commands. */
install_element(VIEW_NODE, &show_ip_bgp_neighbors_cmd);
+ install_element(VIEW_NODE,
+ &show_ip_bgp_neighbors_graceful_restart_cmd);
+
/* "show [ip] bgp peer-group" commands. */
install_element(VIEW_NODE, &show_ip_bgp_peer_groups_cmd);
diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h
index 5f3ce9cd8e..2e33ed59b9 100644
--- a/bgpd/bgp_vty.h
+++ b/bgpd/bgp_vty.h
@@ -22,7 +22,7 @@
#define _QUAGGA_BGP_VTY_H
#include "bgpd/bgpd.h"
-
+#include "stream.h"
struct bgp;
#define BGP_INSTANCE_HELP_STR "BGP view\nBGP VRF\nView/VRF name\n"
@@ -46,6 +46,110 @@ struct bgp;
"Address Family modifier\n" \
"Address Family modifier\n"
+#define SHOW_GR_HEADER \
+ "Codes: GR - Graceful Restart," \
+ " * - Inheriting Global GR Config,\n" \
+ " Restart - GR Mode-Restarting," \
+ " Helper - GR Mode-Helper,\n" \
+ " Disable - GR Mode-Disable.\n\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); \
+ } while (0)
+
+#define VTY_BGP_GR_DEFINE_LOOP_VARIABLE \
+ struct peer *peer_loop = NULL; \
+ struct listnode *node = NULL; \
+ struct listnode *nnode = NULL; \
+ bool gr_router_detected = false
+
+#define VTY_BGP_GR_ROUTER_DETECT( \
+ _bgp, _peer, _peer_list) \
+ do { \
+ if (_peer->bgp->t_startup) \
+ bgp_peer_gr_flags_update(_peer); \
+ for (ALL_LIST_ELEMENTS(_peer_list, \
+ node, nnode, peer_loop)) { \
+ if (CHECK_FLAG(peer_loop->flags,\
+ PEER_FLAG_GRACEFUL_RESTART)) \
+ gr_router_detected = true; \
+ } \
+ } while (0)
+
+
+#define VTY_SEND_BGP_GR_CAPABILITY_TO_ZEBRA(_bgp, _ret) \
+ do { \
+ if (gr_router_detected && \
+ _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+ if (bgp_zebra_send_capabilities(_bgp, false)) \
+ _ret = BGP_ERR_INVALID_VALUE;\
+ } else if (!gr_router_detected && \
+ _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \
+ if (bgp_zebra_send_capabilities(_bgp, true)) \
+ _ret = BGP_ERR_INVALID_VALUE;\
+ } \
+ } while (0)
+
+#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \
+ _bgp, _peer_list, _ret) \
+ do { \
+ struct peer *peer_loop; \
+ bool gr_router_detected = false; \
+ struct listnode *node = {0}; \
+ struct listnode *nnode = {0}; \
+ for (ALL_LIST_ELEMENTS( \
+ _peer_list, node, \
+ nnode, peer_loop)) { \
+ if (peer_loop->bgp->t_startup) \
+ bgp_peer_gr_flags_update(peer_loop); \
+ if (CHECK_FLAG( \
+ peer_loop->flags, \
+ PEER_FLAG_GRACEFUL_RESTART)) \
+ gr_router_detected = true; \
+ } \
+ if (gr_router_detected && \
+ _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+ if (bgp_zebra_send_capabilities(_bgp, false)) \
+ _ret = BGP_ERR_INVALID_VALUE;\
+ } else if (!gr_router_detected && \
+ _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \
+ if (bgp_zebra_send_capabilities(_bgp, true)) \
+ _ret = BGP_ERR_INVALID_VALUE;\
+ } \
+ } while (0)
+
+
+#define PRINT_EOR(_eor_flag) \
+ do { \
+ if (eor_flag) \
+ vty_out(vty, "Yes\n"); \
+ else \
+ vty_out(vty, "No\n"); \
+ } while (0)
+
+#define PRINT_EOR_JSON(_eor_flag) \
+ do { \
+ if (eor_flag) \
+ json_object_boolean_true_add( \
+ json_endofrib_status, \
+ "endOfRibSentAfterUpdate"); \
+ else \
+ json_object_boolean_false_add( \
+ json_endofrib_status, \
+ "endOfRibSentAfterUpdate"); \
+ } while (0)
+
extern void bgp_vty_init(void);
extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index c99ddaf0a6..03d5cd984f 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2437,6 +2437,7 @@ static void bgp_zebra_connected(struct zclient *zclient)
/* TODO - What if we have peers and networks configured, do we have to
* kick-start them?
*/
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer);
}
static int bgp_zebra_process_local_es(ZAPI_CALLBACK_ARGS)
@@ -3016,3 +3017,157 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
return;
}
}
+
+/* Send capabilities to RIB */
+int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable)
+{
+ struct zapi_cap api;
+ int ret = BGP_GR_SUCCESS;
+
+ if (zclient == NULL) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("zclient invalid");
+ return BGP_GR_FAILURE;
+ }
+
+ /* Check if the client is connected */
+ if ((zclient->sock < 0) || (zclient->t_connect)) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("client not connected");
+ return BGP_GR_FAILURE;
+ }
+
+ /* Check if capability is already sent. If the flag force is set
+ * send the capability since this can be initial bgp configuration
+ */
+ memset(&api, 0, sizeof(struct zapi_cap));
+ if (disable) {
+ api.cap = ZEBRA_CLIENT_GR_DISABLE;
+ api.vrf_id = bgp->vrf_id;
+ } else {
+ api.cap = ZEBRA_CLIENT_GR_CAPABILITIES;
+ api.stale_removal_time = bgp->rib_stale_time;
+ api.vrf_id = bgp->vrf_id;
+ }
+
+ if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES,
+ zclient, &api) < 0) {
+ zlog_err("error sending capability");
+ ret = BGP_GR_FAILURE;
+ } else {
+ if (disable)
+ bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE;
+ else
+ bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE;
+
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("send capabilty success");
+ ret = BGP_GR_SUCCESS;
+ }
+ return ret;
+}
+
+/* Send route update pesding or completed status to RIB for the
+ * specific AFI, SAFI
+ */
+int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type)
+{
+ struct zapi_cap api = {0};
+
+ if (zclient == NULL) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("zclient == NULL, invalid");
+ return BGP_GR_FAILURE;
+ }
+
+ /* Check if the client is connected */
+ if ((zclient->sock < 0) || (zclient->t_connect)) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("client not connected");
+ return BGP_GR_FAILURE;
+ }
+
+ api.afi = afi;
+ api.safi = safi;
+ api.vrf_id = vrf_id;
+ api.cap = type;
+
+ if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES,
+ zclient, &api) < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("error sending capability");
+ return BGP_GR_FAILURE;
+ }
+ return BGP_GR_SUCCESS;
+}
+
+
+int zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
+ struct zapi_cap *api)
+{
+ struct stream *s;
+
+ if (zclient == NULL)
+ return -1;
+
+ s = zclient->obuf;
+ stream_reset(s);
+ zclient_create_header(s, cmd, 0);
+ stream_putl(s, api->cap);
+ switch (api->cap) {
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ stream_putl(s, api->stale_removal_time);
+ stream_putl(s, api->vrf_id);
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ stream_putl(s, api->afi);
+ stream_putl(s, api->safi);
+ stream_putl(s, api->vrf_id);
+ break;
+ case ZEBRA_CLIENT_GR_DISABLE:
+ stream_putl(s, api->vrf_id);
+ break;
+ default:
+ break;
+ }
+
+ /* Put length at the first point of the stream */
+ stream_putw_at(s, 0, stream_get_endp(s));
+
+ return zclient_send_message(zclient);
+}
+
+/* Send RIB stale timer update */
+int bgp_zebra_stale_timer_update(struct bgp *bgp)
+{
+ struct zapi_cap api;
+
+ if (zclient == NULL) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("zclient invalid");
+ return BGP_GR_FAILURE;
+ }
+
+ /* Check if the client is connected */
+ if ((zclient->sock < 0) || (zclient->t_connect)) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("client not connected");
+ return BGP_GR_FAILURE;
+ }
+
+ memset(&api, 0, sizeof(struct zapi_cap));
+ api.cap = ZEBRA_CLIENT_RIB_STALE_TIME;
+ api.stale_removal_time = bgp->rib_stale_time;
+ api.vrf_id = bgp->vrf_id;
+ if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES,
+ zclient, &api) < 0) {
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("error sending capability");
+ return BGP_GR_FAILURE;
+ }
+ if (BGP_DEBUG(zebra, ZEBRA))
+ zlog_debug("send capabilty success");
+ return BGP_GR_SUCCESS;
+}
diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h
index 62c311cc1d..c0e305286e 100644
--- a/bgpd/bgp_zebra.h
+++ b/bgpd/bgp_zebra.h
@@ -80,11 +80,11 @@ extern int bgp_zebra_num_connects(void);
extern bool bgp_zebra_nexthop_set(union sockunion *, union sockunion *,
struct bgp_nexthop *, struct peer *);
-
struct bgp_pbr_action;
struct bgp_pbr_match;
struct bgp_pbr_rule;
struct bgp_pbr_match_entry;
+
extern void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra,
struct bgp_pbr_rule *pbr,
bool install);
@@ -98,5 +98,8 @@ extern void bgp_send_pbr_iptable(struct bgp_pbr_action *pba,
extern void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh,
afi_t afi, uint32_t table_id, bool announce);
-
+extern int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable);
+extern int bgp_zebra_update(afi_t afi, safi_t safi, vrf_id_t vrf_id,
+ int type);
+extern int bgp_zebra_stale_timer_update(struct bgp *bgp);
#endif /* _QUAGGA_BGP_ZEBRA_H */
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 9b0e81491a..d866ba7f5d 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1102,6 +1102,119 @@ struct peer *peer_unlock_with_caller(const char *name, struct peer *peer)
return peer;
}
+/* BGP GR changes */
+
+int bgp_global_gr_init(struct bgp *bgp)
+{
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%s called ..", __func__);
+
+ int local_GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE][BGP_GLOBAL_GR_EVENT_CMD] = {
+ /* GLOBAL_HELPER Mode */
+ {
+ /*Event -> */
+ /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
+ GLOBAL_GR, GLOBAL_INVALID,
+ /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+ GLOBAL_DISABLE, GLOBAL_INVALID
+ },
+ /* GLOBAL_GR Mode */
+ {
+ /*Event -> */
+ /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
+ GLOBAL_INVALID, GLOBAL_HELPER,
+ /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+ GLOBAL_DISABLE, GLOBAL_INVALID
+ },
+ /* GLOBAL_DISABLE Mode */
+ {
+ /*Event -> */
+ /*GLOBAL_GR_cmd */ /*no_Global_GR_cmd*/
+ GLOBAL_GR, GLOBAL_INVALID,
+ /*GLOBAL_DISABLE_cmd*//*no_Global_Disable_cmd*/
+ GLOBAL_INVALID, GLOBAL_HELPER
+ },
+ /* GLOBAL_INVALID Mode */
+ {
+ /*Event -> */
+ /*GLOBAL_GR_cmd*/ /*no_Global_GR_cmd*/
+ GLOBAL_INVALID, GLOBAL_INVALID,
+ /*GLOBAL_DISABLE_cmd*/ /*no_Global_Disable_cmd*/
+ GLOBAL_INVALID, GLOBAL_INVALID
+ }
+ };
+ memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM,
+ sizeof(local_GLOBAL_GR_FSM));
+
+ bgp->global_gr_present_state = GLOBAL_HELPER;
+ bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE;
+
+ return BGP_GR_SUCCESS;
+}
+
+int bgp_peer_gr_init(struct peer *peer)
+{
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("%s called ..", __func__);
+
+ struct bgp_peer_gr local_Peer_GR_FSM[BGP_PEER_GR_MODE]
+ [BGP_PEER_GR_EVENT_CMD] = {
+ {
+ /* PEER_HELPER Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_GR, bgp_peer_gr_action }, {PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ {PEER_DISABLE, bgp_peer_gr_action }, {PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_INVALID, NULL }, {PEER_GLOBAL_INHERIT,
+ bgp_peer_gr_action }
+ },
+ {
+ /* PEER_GR Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT,
+ bgp_peer_gr_action },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ {PEER_DISABLE, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+ },
+ {
+ /* PEER_DISABLE Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ { PEER_INVALID, NULL }, { PEER_GLOBAL_INHERIT,
+ bgp_peer_gr_action },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+ },
+ {
+ /* PEER_INVALID Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_INVALID, NULL }, { PEER_INVALID, NULL },
+ },
+ {
+ /* PEER_GLOBAL_INHERIT Mode */
+ /* Event-> */ /* PEER_GR_CMD */ /* NO_PEER_GR_CMD */
+ { PEER_GR, bgp_peer_gr_action }, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_DISABLE_CMD */ /* NO_PEER_DISABLE_CMD */
+ { PEER_DISABLE, bgp_peer_gr_action}, { PEER_INVALID, NULL },
+ /* Event-> */ /* PEER_HELPER_cmd */ /* NO_PEER_HELPER_CMD */
+ { PEER_HELPER, bgp_peer_gr_action }, { PEER_INVALID, NULL }
+ }
+ };
+ memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM,
+ sizeof(local_Peer_GR_FSM));
+ peer->peer_gr_present_state = PEER_GLOBAL_INHERIT;
+ bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT);
+
+ return BGP_GR_SUCCESS;
+}
/* Allocate new peer object, implicitely locked. */
struct peer *peer_new(struct bgp *bgp)
@@ -1153,6 +1266,9 @@ struct peer *peer_new(struct bgp *bgp)
SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
+ /* Initialize per peer bgp GR FSM */
+ bgp_peer_gr_init(peer);
+
/* Create buffers. */
peer->ibuf = stream_fifo_new();
peer->obuf = stream_fifo_new();
@@ -1212,6 +1328,9 @@ void peer_xfer_config(struct peer *peer_dst, struct peer *peer_src)
peer_dst->flags = peer_src->flags;
peer_dst->cap = peer_src->cap;
+ peer_dst->peer_gr_present_state = peer_src->peer_gr_present_state;
+ peer_dst->peer_gr_new_status_flag = peer_src->peer_gr_new_status_flag;
+
peer_dst->local_as = peer_src->local_as;
peer_dst->port = peer_src->port;
(void)peer_sort(peer_dst);
@@ -1534,6 +1653,11 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
else if (!active && peer_active(peer))
bgp_timer_set(peer);
+ bgp_peer_gr_flags_update(peer);
+ BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(
+ bgp,
+ bgp->peer);
+
return peer;
}
@@ -2098,7 +2222,7 @@ int peer_afc_set(struct peer *peer, afi_t afi, safi_t safi, int enable)
return peer_deactivate(peer, afi, safi);
}
-static void peer_nsf_stop(struct peer *peer)
+void peer_nsf_stop(struct peer *peer)
{
afi_t afi;
safi_t safi;
@@ -2902,6 +3026,12 @@ static struct bgp *bgp_create(as_t *as, const char *name,
multipath_num, 0);
bgp_maximum_paths_set(bgp, afi, safi, BGP_PEER_IBGP,
multipath_num, 0);
+ /* Initialize graceful restart info */
+ bgp->gr_info[afi][safi].eor_required = 0;
+ bgp->gr_info[afi][safi].eor_received = 0;
+ bgp->gr_info[afi][safi].t_select_deferral = NULL;
+ bgp->gr_info[afi][safi].t_route_select = NULL;
+ bgp->gr_info[afi][safi].route_list = list_new();
}
bgp->v_update_delay = BGP_UPDATE_DELAY_DEF;
@@ -2911,6 +3041,8 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp_timers_unset(bgp);
bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
bgp->stalepath_time = BGP_DEFAULT_STALEPATH_TIME;
+ bgp->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME;
+ bgp->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME;
bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT;
bgp->dynamic_neighbors_count = 0;
bgp->ebgp_requires_policy = DEFAULT_EBGP_POLICY_DISABLED;
@@ -2941,14 +3073,11 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->vpn_policy[afi].export_vrf->del =
bgp_vrf_string_name_delete;
}
- if (name) {
+ if (name)
bgp->name = XSTRDUP(MTYPE_BGP, name);
- } else {
- /* TODO - The startup timer needs to be run for the whole of BGP
- */
- thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
- bgp->restart_time, &bgp->t_startup);
- }
+
+ thread_add_timer(bm->master, bgp_startup_timer_expire, bgp,
+ bgp->restart_time, &bgp->t_startup);
/* printable name we can use in debug messages */
if (inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
@@ -2990,6 +3119,9 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp_evpn_init(bgp);
bgp_pbr_init(bgp);
+
+ /*initilize global GR FSM */
+ bgp_global_gr_init(bgp);
return bgp;
}
@@ -3233,7 +3365,9 @@ int bgp_delete(struct bgp *bgp)
struct listnode *node, *next;
struct vrf *vrf;
afi_t afi;
+ safi_t safi;
int i;
+ struct graceful_restart_info *gr_info;
assert(bgp);
@@ -3247,6 +3381,19 @@ int bgp_delete(struct bgp *bgp)
/* Set flag indicating bgp instance delete in progress */
bgp_flag_set(bgp, BGP_FLAG_DELETE_IN_PROGRESS);
+ /* Delete the graceful restart info */
+ FOREACH_AFI_SAFI (afi, safi) {
+ gr_info = &bgp->gr_info[afi][safi];
+ if (gr_info) {
+ BGP_TIMER_OFF(gr_info->t_select_deferral);
+ gr_info->t_select_deferral = NULL;
+ BGP_TIMER_OFF(gr_info->t_route_select);
+ gr_info->t_route_select = NULL;
+ if (gr_info->route_list)
+ list_delete(&gr_info->route_list);
+ }
+ }
+
if (BGP_DEBUG(zebra, ZEBRA)) {
if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
zlog_debug("Deleting Default VRF");
@@ -7099,3 +7246,33 @@ struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
return peer;
}
+void bgp_gr_apply_running_config(void)
+{
+ struct peer *peer = NULL;
+ struct bgp *bgp = NULL;
+ struct listnode *node, *nnode;
+ bool gr_router_detected = false;
+
+ if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART))
+ zlog_debug("[BGP_GR] %s called !",
+ __func__);
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ bgp_peer_gr_flags_update(peer);
+ if (CHECK_FLAG(peer->flags,
+ PEER_FLAG_GRACEFUL_RESTART))
+ gr_router_detected = true;
+ }
+
+ if (gr_router_detected &&
+ bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) {
+ bgp_zebra_send_capabilities(bgp, true);
+ } else if (!gr_router_detected &&
+ bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) {
+ bgp_zebra_send_capabilities(bgp, false);
+ }
+
+ gr_router_detected = false;
+ }
+}
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 4c4787ed5b..3f33139ef2 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -65,6 +65,12 @@ enum { AS_UNSPECIFIED = 0,
AS_EXTERNAL,
};
+/* Zebra Gracaful Restart states */
+enum zebra_gr_mode {
+ ZEBRA_GR_DISABLE = 0,
+ ZEBRA_GR_ENABLE
+};
+
/* Typedef BGP specific types. */
typedef uint32_t as_t;
typedef uint16_t as16_t; /* we may still encounter 16 Bit asnums */
@@ -232,6 +238,52 @@ enum bgp_instance_type {
BGP_INSTANCE_TYPE_VIEW
};
+#define BGP_SEND_EOR(bgp, afi, safi) \
+ (!bgp_flag_check(bgp, BGP_FLAG_GR_DISABLE_EOR) && \
+ ((bgp->gr_info[afi][safi].t_select_deferral == NULL) || \
+ (bgp->gr_info[afi][safi].eor_required == \
+ bgp->gr_info[afi][safi].eor_received)))
+
+/* BGP GR Global ds */
+
+#define BGP_GLOBAL_GR_MODE 4
+#define BGP_GLOBAL_GR_EVENT_CMD 4
+
+/* Graceful restart selection deferral timer info */
+struct graceful_restart_info {
+ /* Count of EOR message expected */
+ uint32_t eor_required;
+ /* Count of EOR received */
+ uint32_t eor_received;
+ /* Deferral Timer */
+ struct thread *t_select_deferral;
+ /* Route list */
+ struct list *route_list;
+ /* Best route select */
+ struct thread *t_route_select;
+ /* AFI, SAFI enabled */
+ bool af_enabled[AFI_MAX][SAFI_MAX];
+ /* Route update completed */
+ bool route_sync[AFI_MAX][SAFI_MAX];
+};
+
+enum global_mode {
+ GLOBAL_HELPER = 0, /* This is the default mode */
+ GLOBAL_GR,
+ GLOBAL_DISABLE,
+ GLOBAL_INVALID
+};
+
+enum global_gr_command {
+ GLOBAL_GR_CMD = 0,
+ NO_GLOBAL_GR_CMD,
+ GLOBAL_DISABLE_CMD,
+ NO_GLOBAL_DISABLE_CMD
+};
+
+#define BGP_GR_SUCCESS 0
+#define BGP_GR_FAILURE 1
+
/* BGP instance structure. */
struct bgp {
/* AS number of this BGP instance. */
@@ -356,7 +408,10 @@ struct bgp {
#define BGP_FLAG_IMPORT_CHECK (1 << 9)
#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 10)
#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 11)
+
+/* This flag is set when we have full BGP Graceful-Restart mode enable */
#define BGP_FLAG_GRACEFUL_RESTART (1 << 12)
+
#define BGP_FLAG_ASPATH_CONFED (1 << 13)
#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 14)
#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 15)
@@ -367,6 +422,17 @@ struct bgp {
#define BGP_FLAG_GR_PRESERVE_FWD (1 << 20)
#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 21)
#define BGP_FLAG_DELETE_IN_PROGRESS (1 << 22)
+#define BGP_FLAG_SELECT_DEFER_DISABLE (1 << 23)
+#define BGP_FLAG_GR_DISABLE_EOR (1 << 24)
+
+ enum global_mode GLOBAL_GR_FSM[BGP_GLOBAL_GR_MODE]
+ [BGP_GLOBAL_GR_EVENT_CMD];
+ enum global_mode global_gr_present_state;
+
+ /* This variable stores the current Graceful Restart state of Zebra
+ * - ZEBRA_GR_ENABLE / ZEBRA_GR_DISABLE
+ */
+ enum zebra_gr_mode present_zebra_gr_state;
/* BGP Per AF flags */
uint16_t af_flags[AFI_MAX][SAFI_MAX];
@@ -462,7 +528,12 @@ struct bgp {
/* BGP graceful restart */
uint32_t restart_time;
uint32_t stalepath_time;
+ uint32_t select_defer_time;
+ struct graceful_restart_info gr_info[AFI_MAX][SAFI_MAX];
+ uint32_t rib_stale_time;
+#define BGP_ROUTE_SELECT_DELAY 1
+#define BGP_MAX_BEST_ROUTE_SELECT 10000
/* Maximum-paths configuration */
struct bgp_maxpaths_cfg {
uint16_t maxpaths_ebgp;
@@ -548,7 +619,6 @@ struct bgp {
#define BGP_VRF_RD_CFGD (1 << 3)
#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 4)
-
/* unique ID for auto derivation of RD for this vrf */
uint16_t vrf_rd_id;
@@ -589,6 +659,13 @@ DECLARE_HOOK(bgp_inst_config_write,
(struct bgp *bgp, struct vty *vty),
(bgp, vty))
+ /* Thread callback information */
+ struct afi_safi_info {
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+ };
+
#define BGP_ROUTE_ADV_HOLD(bgp) (bgp->main_peers_update_hold)
#define IS_BGP_INST_KNOWN_TO_ZEBRA(bgp) \
@@ -596,6 +673,9 @@ DECLARE_HOOK(bgp_inst_config_write,
|| (bgp->inst_type == BGP_INSTANCE_TYPE_VRF \
&& bgp->vrf_id != VRF_UNKNOWN))
+#define BGP_SELECT_DEFER_DISABLE(bgp) \
+ (bgp_flag_check(bgp, BGP_FLAG_SELECT_DEFER_DISABLE))
+
/* BGP peer-group support. */
struct peer_group {
/* Name of the peer-group. */
@@ -726,6 +806,36 @@ struct peer_af {
safi_t safi;
int afid;
};
+/* BGP GR per peer ds */
+
+#define BGP_PEER_GR_MODE 5
+#define BGP_PEER_GR_EVENT_CMD 6
+
+enum peer_mode {
+ PEER_HELPER = 0,
+ PEER_GR,
+ PEER_DISABLE,
+ PEER_INVALID,
+ PEER_GLOBAL_INHERIT /* This is the default mode */
+
+};
+
+enum peer_gr_command {
+ PEER_GR_CMD = 0,
+ NO_PEER_GR_CMD,
+ PEER_DISABLE_CMD,
+ NO_PEER_DISABLE_CMD,
+ PEER_HELPER_CMD,
+ NO_PEER_HELPER_CMD
+};
+
+typedef unsigned int (*bgp_peer_gr_action_ptr)(struct peer *, int, int);
+
+struct bgp_peer_gr {
+ enum peer_mode next_state;
+ bgp_peer_gr_action_ptr action_fun;
+};
+
/* BGP neighbor structure. */
struct peer {
@@ -947,11 +1057,36 @@ struct peer {
#define PEER_FLAG_LOCAL_AS (1 << 21) /* local-as */
#define PEER_FLAG_UPDATE_SOURCE (1 << 22) /* update-source */
+ /* BGP-GR Peer related flags */
+#define PEER_FLAG_GRACEFUL_RESTART_HELPER (1 << 23) /* Helper */
+#define PEER_FLAG_GRACEFUL_RESTART (1 << 24) /* Graceful Restart */
+#define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1 << 25) /* Global-Inherit */
+
+ /*
+ *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
+ *& PEER_FLAG_GRACEFUL_RESTART_HELPER
+ *and PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT
+ */
+
+ struct bgp_peer_gr PEER_GR_FSM[BGP_PEER_GR_MODE][BGP_PEER_GR_EVENT_CMD];
+ enum peer_mode peer_gr_present_state;
+ /* Non stop forwarding afi-safi count for BGP gr feature*/
+ uint8_t nsf_af_count;
+
+ uint8_t peer_gr_new_status_flag;
+#define PEER_GRACEFUL_RESTART_NEW_STATE_HELPER (1 << 0)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_RESTART (1 << 1)
+#define PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT (1 << 2)
+
/* outgoing message sent in CEASE_ADMIN_SHUTDOWN notify */
char *tx_shutdown_message;
/* NSF mode (graceful restart) */
uint8_t nsf[AFI_MAX][SAFI_MAX];
+ /* EOR Send time */
+ time_t eor_stime[AFI_MAX][SAFI_MAX];
+ /* Last update packet sent time */
+ time_t pkt_stime[AFI_MAX][SAFI_MAX];
/* Peer Per AF flags */
/*
@@ -1456,6 +1591,8 @@ struct bgp_nlri {
/* BGP graceful restart */
#define BGP_DEFAULT_RESTART_TIME 120
#define BGP_DEFAULT_STALEPATH_TIME 360
+#define BGP_DEFAULT_SELECT_DEFERRAL_TIME 360
+#define BGP_DEFAULT_RIB_STALE_TIME 500
/* BGP uptime string length. */
#define BGP_UPTIME_LEN 25
@@ -1521,6 +1658,11 @@ enum bgp_clear_type {
#define BGP_ERR_INVALID_FOR_DIRECT_PEER -34
#define BGP_ERR_PEER_SAFI_CONFLICT -35
+/* BGP GR ERRORS */
+#define BGP_ERR_GR_INVALID_CMD -36
+#define BGP_ERR_GR_OPERATION_FAILED -37
+#define BGP_GR_NO_OPERATION -38
+
/*
* Enumeration of different policy kinds a peer can be configured with.
*/
@@ -1773,6 +1915,36 @@ extern int peer_af_delete(struct peer *, afi_t, safi_t);
extern void bgp_close(void);
extern void bgp_free(struct bgp *);
+void bgp_gr_apply_running_config(void);
+
+/* BGP GR */
+int bgp_global_gr_init(struct bgp *bgp);
+int bgp_peer_gr_init(struct peer *peer);
+
+
+#define BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \
+ _bgp, _peer_list) \
+do { \
+ struct peer *peer_loop; \
+ bool gr_router_detected = false; \
+ struct listnode *node = {0}; \
+ struct listnode *nnode = {0}; \
+ for (ALL_LIST_ELEMENTS( \
+ _peer_list, node, \
+ nnode, peer_loop)) { \
+ if (CHECK_FLAG( \
+ peer_loop->flags, \
+ PEER_FLAG_GRACEFUL_RESTART)) \
+ gr_router_detected = true; \
+ } \
+ if (gr_router_detected && \
+ _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \
+ bgp_zebra_send_capabilities(_bgp, false); \
+ } else if (!gr_router_detected && \
+ _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \
+ bgp_zebra_send_capabilities(_bgp, true); \
+ } \
+} while (0)
static inline struct bgp *bgp_lock(struct bgp *bgp)
{
@@ -1962,5 +2134,6 @@ extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
/* Hooks */
DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer))
+void peer_nsf_stop(struct peer *peer);
#endif /* _QUAGGA_BGPD_H */
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index d3ac4b22ab..81b4e34647 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -694,6 +694,181 @@ from eBGP peers, :ref:`bgp-route-selection`.
MED as an intra-AS metric to steer equal-length AS_PATH routes to, e.g.,
desired exit points.
+
+.. _bgp-graceful-restart:
+
+Graceful Restart
+----------------
+
+BGP graceful restart functionality as defined in
+`RFC-4724 <https://tools.ietf.org/html/rfc4724/>`_ defines the mechanisms that
+allows BGP speaker to continue to forward data packets along known routes
+while the routing protocol information is being restored.
+
+
+Usually, when BGP on a router restarts, all the BGP peers detect that the
+session went down and then came up. This "down/up" transition results in a
+"routing flap" and causes BGP route re-computation, generation of BGP routing
+updates, and unnecessary churn to the forwarding tables.
+
+The following functionality is provided by graceful restart:
+
+1. The feature allows the restarting router to indicate to the helping peer the
+ routes it can preserve in its forwarding plane during control plane restart
+ by sending graceful restart capability in the OPEN message sent during
+ session establishment.
+2. The feature allows helping router to advertise to all other peers the routes
+ received from the restarting router which are preserved in the forwarding
+ plane of the restarting router during control plane restart.
+
+
+::
+
+
+
+ (R1)-----------------------------------------------------------------(R2)
+
+ 1. BGP Graceful Restart Capability exchanged between R1 & R2.
+
+ <--------------------------------------------------------------------->
+
+ 2. Kill BGP Process at R1.
+
+ ---------------------------------------------------------------------->
+
+ 3. R2 Detects the above BGP Restart & verifies BGP Restarting
+ Capability of R1.
+
+ 4. Start BGP Process at R1.
+
+ 5. Re-establish the BGP session between R1 & R2.
+
+ <--------------------------------------------------------------------->
+
+ 6. R2 Send initial route updates, followed by End-Of-Rib.
+
+ <----------------------------------------------------------------------
+
+ 7. R1 was waiting for End-Of-Rib from R2 & which has been received
+ now.
+
+ 8. R1 now runs BGP Best-Path algorithm. Send Initial BGP Update,
+ followed by End-Of Rib
+
+ <--------------------------------------------------------------------->
+
+
+.. _bgp-end-of-rib-message:
+
+End-of-RIB (EOR) message
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+An UPDATE message with no reachable Network Layer Reachability Information
+(NLRI) and empty withdrawn NLRI is specified as the End-of-RIB marker that can
+be used by a BGP speaker to indicate to its peer the completion of the initial
+routing update after the session is established.
+
+For the IPv4 unicast address family, the End-of-RIB marker is an UPDATE message
+with the minimum length. For any other address family, it is an UPDATE message
+that contains only the MP_UNREACH_NLRI attribute with no withdrawn routes for
+that <AFI, SAFI>.
+
+Although the End-of-RIB marker is specified for the purpose of BGP graceful
+restart, it is noted that the generation of such a marker upon completion of
+the initial update would be useful for routing convergence in general, and thus
+the practice is recommended.
+
+.. _bgp-route-selection-deferral-timer:
+
+Route Selection Deferral Timer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Specifies the time the restarting router defers the route selection process
+after restart.
+
+Restarting Router : The usage of route election deferral timer is specified
+in https://tools.ietf.org/html/rfc4724#section-4.1
+
+Once the session between the Restarting Speaker and the Receiving Speaker is
+re-established, the Restarting Speaker will receive and process BGP messages
+from its peers.
+
+However, it MUST defer route selection for an address family until it either.
+
+1. Receives the End-of-RIB marker from all its peers (excluding the ones with
+ the "Restart State" bit set in the received capability and excluding the ones
+ that do not advertise the graceful restart capability).
+2. The Selection_Deferral_Timer timeout.
+
+.. index:: bgp graceful-restart select-defer-time (0-3600)
+.. clicmd:: bgp graceful-restart select-defer-time (0-3600)
+
+ This is command, will set deferral time to value specified.
+
+
+.. index:: bgp graceful-restart rib-stale-time (1-3600)
+.. clicmd:: bgp graceful-restart rib-stale-time (1-3600)
+
+ This is command, will set the time for which stale routes are kept in RIB.
+
+.. _bgp-per-peer-graceful-restart:
+
+BGP Per Peer Graceful Restart
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Ability to enable and disable graceful restart, helper and no GR at all mode
+functionality at peer level.
+
+So bgp graceful restart can be enabled at modes global BGP level or at per
+peer level. There are two FSM, one for BGP GR global mode and other for peer
+per GR.
+
+Default global mode is helper and default peer per mode is inherit from global.
+If per peer mode is configured, the GR mode of this particular peer will
+override the global mode.
+
+.. _bgp-GR-global-mode-cmd:
+
+BGP GR Global Mode Commands
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. index:: bgp graceful-restart
+.. clicmd:: bgp graceful-restart
+
+ This command will enable BGP graceful restart ifunctionality at the global
+ level.
+
+.. index:: bgp graceful-restart disable
+.. clicmd:: bgp graceful-restart disable
+
+ This command will disable both the functionality graceful restart and helper
+ mode.
+
+
+.. _bgp-GR-peer-mode-cmd:
+
+BGP GR Peer Mode Commands
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. index:: neighbor A.B.C.D graceful-restart
+.. clicmd:: neighbor A.B.C.D graceful-restart
+
+ This command will enable BGP graceful restart ifunctionality at the peer
+ level.
+
+.. index:: neighbor A.B.C.D graceful-restart-helper
+.. clicmd:: neighbor A.B.C.D graceful-restart-helper
+
+ This command will enable BGP graceful restart helper only functionality
+ at the peer level.
+
+.. index:: neighbor A.B.C.D graceful-restart-disable
+.. clicmd:: neighbor A.B.C.D graceful-restart-disable
+
+ This command will disable the entire BGP graceful restart functionality
+ at the peer level.
+
+
.. _bgp-network:
Networks
diff --git a/lib/command.h b/lib/command.h
index c8dd04604d..ea8a76a964 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -418,8 +418,23 @@ struct cmd_node {
#define DAEMONS_LIST \
"<zebra|ripd|ripngd|ospfd|ospf6d|bgpd|isisd|pbrd|fabricd|pimd|staticd|sharpd|vrrpd|ldpd>"
+/* Graceful Restart cli help strings */
+#define GR_CMD "Global Graceful Restart command\n"
+#define NO_GR_CMD "Undo Global Graceful Restart command\n"
+#define GR "Global Graceful Restart - GR Mode\n"
+#define GR_DISABLE "Global Graceful Restart - Disable Mode\n"
+#define NO_GR_DISABLE "Undo Global Graceful Restart - Disable Mode\n"
+#define GR_DEBUG "Graceful Restart - Enable Debug Logs\n"
+#define GR_SHOW "Graceful Restart - Show command for Global and all neighbor mode\n"
+#define GR_NEIGHBOR_CMD "Graceful Restart command for a neighbor\n"
+#define NO_GR_NEIGHBOR_CMD "Undo Graceful Restart command for a neighbor\n"
+#define GR_NEIGHBOR_DISABLE_CMD "Graceful Restart Disable command for a neighbor\n"
+#define NO_GR_NEIGHBOR_DISABLE_CMD "Undo Graceful Restart Disable command for a neighbor\n"
+#define GR_NEIGHBOR_HELPER_CMD "Graceful Restart Helper command for a neighbor\n"
+#define NO_GR_NEIGHBOR_HELPER_CMD "Undo Graceful Restart Helper command for a neighbor\n"
+
/* Prototypes. */
-extern void install_node(struct cmd_node *, int (*)(struct vty *));
+extern void install_node(struct cmd_node *node, int (*)(struct vty *));
extern void install_default(enum node_type);
extern void install_element(enum node_type, const struct cmd_element *);
diff --git a/lib/zclient.c b/lib/zclient.c
index b2c74cd0b9..7ddf0085de 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -3299,3 +3299,32 @@ void zclient_interface_set_master(struct zclient *client,
stream_putw_at(s, 0, stream_get_endp(s));
zclient_send_message(client);
}
+
+/* Process capabilities message from zebra */
+int zapi_capabilities_decode(struct stream *s, struct zapi_cap *api)
+{
+ memset(api, 0, sizeof(*api));
+
+ STREAM_GETL(s, api->cap);
+ switch (api->cap) {
+ case ZEBRA_CLIENT_GR_CAPABILITIES:
+ case ZEBRA_CLIENT_RIB_STALE_TIME:
+ STREAM_GETL(s, api->stale_removal_time);
+ STREAM_GETL(s, api->vrf_id);
+ break;
+ case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE:
+ case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING:
+ STREAM_GETL(s, api->afi);
+ STREAM_GETL(s, api->safi);
+ STREAM_GETL(s, api->vrf_id);
+ break;
+ case ZEBRA_CLIENT_GR_DISABLE:
+ STREAM_GETL(s, api->vrf_id);
+ break;
+ default:
+ break;
+ }
+
+stream_failure:
+ return 0;
+}
diff --git a/lib/zclient.h b/lib/zclient.h
index d1aa42da6d..bbc70c3835 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -73,6 +73,14 @@ typedef uint16_t zebra_size_t;
#define ZEBRA_FEC_REGISTER_LABEL 0x1
#define ZEBRA_FEC_REGISTER_LABEL_INDEX 0x2
+/* Client Graceful Restart */
+#define ZEBRA_CLIENT_GR_CAPABILITIES 0x1
+#define ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE 0x2
+#define ZEBRA_CLIENT_ROUTE_UPDATE_PENDING 0x3
+#define ZEBRA_CLIENT_GR_DISABLE 0x4
+#define ZEBRA_CLIENT_RIB_STALE_TIME 0x5
+#define ZEBRA_CLIENT_GR_ENABLED(X) (X & ZEBRA_CLIENT_GR_CAPABILITIES)
+
extern struct sockaddr_storage zclient_addr;
extern socklen_t zclient_addr_len;
@@ -184,6 +192,7 @@ typedef enum {
ZEBRA_MLAG_CLIENT_UNREGISTER,
ZEBRA_MLAG_FORWARD_MSG,
ZEBRA_ERROR,
+ ZEBRA_CLIENT_CAPABILITIES
} zebra_message_types_t;
enum zebra_error_types {
@@ -222,6 +231,15 @@ struct zclient_capabilities {
enum mlag_role role;
};
+/* Graceful Restart Capabilities message */
+struct zapi_cap {
+ uint32_t cap;
+ uint32_t stale_removal_time;
+ afi_t afi;
+ safi_t safi;
+ vrf_id_t vrf_id;
+};
+
/* Structure for the zebra client. */
struct zclient {
/* The thread master we schedule ourselves on */
@@ -776,4 +794,7 @@ extern void zclient_send_mlag_deregister(struct zclient *client);
extern void zclient_send_mlag_data(struct zclient *client,
struct stream *client_s);
+extern int zclient_capabilities_send(uint32_t cmd, struct zclient *zclient,
+ struct zapi_cap *api);
+extern int zapi_capabilities_decode(struct stream *s, struct zapi_cap *api);
#endif /* _ZEBRA_ZCLIENT_H */
diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c
index 21f4b38773..a51ce4c6bc 100644
--- a/tests/bgpd/test_mpath.c
+++ b/tests/bgpd/test_mpath.c
@@ -297,7 +297,25 @@ struct bgp_node test_rn;
static int setup_bgp_path_info_mpath_update(testcase_t *t)
{
int i;
+ struct bgp *bgp;
+ struct bgp_table *rt;
+ struct route_node *rt_node;
+ as_t asn = 1;
+
+ t->tmp_data = bgp_create_fake(&asn, NULL);
+ if (!t->tmp_data)
+ return -1;
+
+ bgp = t->tmp_data;
+ rt = bgp->rib[AFI_IP][SAFI_UNICAST];
+
+ if (!rt)
+ return -1;
+
str2prefix("42.1.1.0/24", &test_rn.p);
+ rt_node = bgp_node_to_rnode(&test_rn);
+ memcpy((struct route_table *)&rt_node->table, &rt->route_table,
+ sizeof(struct route_table));
setup_bgp_mp_list(t);
for (i = 0; i < test_mp_list_info_count; i++)
bgp_path_info_add(&test_rn, &test_mp_list_info[i]);
@@ -352,7 +370,7 @@ static int cleanup_bgp_path_info_mpath_update(testcase_t *t)
for (i = 0; i < test_mp_list_peer_count; i++)
sockunion_free(test_mp_list_peer[i].su_remote);
- return 0;
+ return bgp_delete((struct bgp *)t->tmp_data);
}
testcase_t test_bgp_path_info_mpath_update = {