/*
- * log.c
- *
- * Contains code that does the logging procedures. Might implement multiple
- * backends (e.g. zebra log, syslog or other logging lib).
+ * logging - alias to zebra log
*/
-enum blog_level {
- /* level vs syslog equivalent */
- BLOG_DEBUG = 0, /* LOG_DEBUG */
- BLOG_INFO = 1, /* LOG_INFO */
- BLOG_WARNING = 2, /* LOG_WARNING */
- BLOG_ERROR = 3, /* LOG_ERR */
- BLOG_FATAL = 4, /* LOG_CRIT */
-};
-void log_init(int foreground, enum blog_level level,
- struct frr_daemon_info *fdi);
-void log_info(const char *fmt, ...);
-void log_debug(const char *fmt, ...);
-void log_warning(const char *fmt, ...);
-void log_error(const char *fmt, ...);
-void log_fatal(const char *fmt, ...);
+#define log_debug zlog_debug
+#define log_info zlog_info
+#define log_warning zlog_warn
+#define log_error zlog_err
+
+#define log_fatal(msg, ...) \
+ do { \
+ zlog_err(msg, ## __VA_ARGS__); \
+ assert(!msg); \
+ abort(); \
+ } while (0)
/*
return -1;
}
if (rv < (ssize_t)datalen)
- log_debug("packet-send: send partial", strerror(errno));
+ log_debug("packet-send: send partial: %s", strerror(errno));
return 0;
}
log_debug("udp-send: loopback failure: (%d) %s", errno, strerror(errno));
return -1;
} else if (wlen < (ssize_t)datalen) {
- log_debug("udp-send: partial send: %ld expected %ld", wlen,
+ log_debug("udp-send: partial send: %zd expected %zu", wlen,
datalen);
return -1;
}
parse_config(conf);
#endif
- /* Initialize logging API. */
- log_init(1, BLOG_DEBUG, &bfdd_di);
+ /* Initialize FRR infrastructure. */
+ master = frr_init();
/* Initialize control socket. */
control_init(ctl_path);
- /* Initialize FRR infrastructure. */
- master = frr_init();
-
/* Initialize BFD data structures. */
bfd_initialize();
if (strlcpy(bpc->bpc_localif, sval,
sizeof(bpc->bpc_localif))
> sizeof(bpc->bpc_localif)) {
- log_debug("\tlocal-interface: %s (truncated)");
+ log_debug("\tlocal-interface: %s (truncated)",
+ sval);
error++;
} else {
log_debug("\tlocal-interface: %s", sval);
bpc->bpc_detectmultiplier =
json_object_get_int64(jo_val);
bpc->bpc_has_detectmultiplier = true;
- log_debug("\tdetect-multiplier: %llu",
+ log_debug("\tdetect-multiplier: %u",
bpc->bpc_detectmultiplier);
} else if (strcmp(key, "receive-interval") == 0) {
bpc->bpc_recvinterval = json_object_get_int64(jo_val);
bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION,
sizeof(bcm) + bcb->bcb_left + 1);
if (bcb->bcb_buf == NULL) {
- log_warning("%s: not enough memory for message size: %u",
+ log_warning("%s: not enough memory for message size: %zu",
__func__, bcb->bcb_left);
control_free(bcs);
return 0;
+++ /dev/null
-/*********************************************************************
- * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF")
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the Free
- * Software Foundation; either version 2 of the License, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; see the file COPYING; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * log.c: implements an abstraction between loggers interface. Implement all
- * log backends in this file.
- *
- * Authors
- * -------
- * Rafael Zalamena <rzalamena@opensourcerouting.org>
- */
-
-#include <zebra.h>
-
-#include "bfd.h"
-
-#include "lib/log_int.h"
-
-void log_msg(int level, const char *fmt, va_list vl);
-
-
-static int log_fg;
-static int log_level = BLOG_DEBUG;
-
-void log_init(int foreground, enum blog_level level,
- struct frr_daemon_info *fdi)
-{
- log_fg = foreground;
- log_level = level;
-
- openzlog(fdi->progname, fdi->logname, 0,
- LOG_CONS | LOG_NDELAY | LOG_PID, LOG_DAEMON);
-}
-
-void log_msg(int level, const char *fmt, va_list vl)
-{
- if (level < log_level)
- return;
-
- switch (level) {
- case BLOG_DEBUG:
- vzlog(LOG_DEBUG, fmt, vl);
- break;
-
- case BLOG_INFO:
- vzlog(LOG_INFO, fmt, vl);
- break;
-
- case BLOG_WARNING:
- vzlog(LOG_WARNING, fmt, vl);
- break;
-
- case BLOG_ERROR:
- vzlog(LOG_ERR, fmt, vl);
- break;
-
- case BLOG_FATAL:
- vzlog(LOG_EMERG, fmt, vl);
- break;
-
- default:
- vfprintf(stderr, fmt, vl);
- break;
- }
-}
-
-void log_info(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_INFO, fmt, vl);
- va_end(vl);
-}
-
-void log_debug(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_DEBUG, fmt, vl);
- va_end(vl);
-}
-
-void log_error(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_ERROR, fmt, vl);
- va_end(vl);
-}
-
-void log_warning(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_WARNING, fmt, vl);
- va_end(vl);
-}
-
-void log_fatal(const char *fmt, ...)
-{
- va_list vl;
-
- va_start(vl, fmt);
- log_msg(BLOG_FATAL, fmt, vl);
- va_end(vl);
-
- exit(1);
-}
bfdd/config.c \
bfdd/control.c \
bfdd/event.c \
- bfdd/log.c \
bfdd/ptm_adapter.c \
# end
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;
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;
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>",
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>",
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;
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");
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;
}
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);
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);
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;
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;
#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))
add_prefix_to_json = 1;
}
- if (json && add_prefix_to_json) {
- json_object_string_add(json_prefix, "prefix",
- prefix_str);
- json_object_int_add(json_prefix, "prefixLen",
- rn->p.prefixlen);
- json_object_object_add(json_prefix, "paths",
- json_paths);
- json_object_object_add(json, prefix_str, json_prefix);
+ if (json) {
+ if (add_prefix_to_json) {
+ json_object_string_add(json_prefix, "prefix",
+ prefix_str);
+ json_object_int_add(json_prefix, "prefixLen",
+ rn->p.prefixlen);
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json, prefix_str,
+ json_prefix);
+ } else {
+ json_object_free(json_paths);
+ json_object_free(json_prefix);
+ json_paths = NULL;
+ json_prefix = NULL;
+ }
}
}
add_prefix_to_json = 1;
}
- if (json && add_prefix_to_json) {
- json_object_string_add(json_prefix, "prefix",
- prefix_str);
- json_object_int_add(json_prefix, "prefixLen",
- rn->p.prefixlen);
- json_object_object_add(json_prefix, "paths",
- json_paths);
- json_object_object_add(json, prefix_str, json_prefix);
+ if (json) {
+ if (add_prefix_to_json) {
+ json_object_string_add(json_prefix, "prefix",
+ prefix_str);
+ json_object_int_add(json_prefix, "prefixLen",
+ rn->p.prefixlen);
+ json_object_object_add(json_prefix, "paths",
+ json_paths);
+ json_object_object_add(json, prefix_str,
+ json_prefix);
+ } else {
+ json_object_free(json_paths);
+ json_object_free(json_prefix);
+ json_paths = NULL;
+ json_prefix = NULL;
+ }
}
}
#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"
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
*/
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);
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
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))) {
/* 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,
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))
+ continue;
+
+ gr_info = &bgp->gr_info[afi][safi];
+ if (!gr_info)
+ continue;
+
+ if (gr_info->eor_required)
+ gr_info->eor_required--;
+
+ if (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->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();
} else {
bgp_peer_conf_if_to_su_update(peer);
}
-
return ret;
}
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;
}
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));
+
+ 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);
+ }
+ 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.
*
int nsf_af_count = 0;
int ret = 0;
struct peer *other;
+ int status;
other = peer->doppelganger;
peer = peer_xfer_conn(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]
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 {
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;
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+}
#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 *);
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 */
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
} 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
frr_config_fork();
/* must be called after fork() */
+ bgp_gr_apply_running_config();
bgp_pthreads_run();
frr_run(bm->master);
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;
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
* 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);
}
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;
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);
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;
}
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))
+ return;
+
+ 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])
+ continue;
+
+ 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)
{
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;
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;
*/
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
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);
}
/* 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);
}
bgp_size_t attribute_len;
bgp_size_t update_len;
bgp_size_t withdraw_len;
+ bool restart = false;
enum NLRI_TYPES {
NLRI_UPDATE,
|| (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
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 */
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;
}
&& 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;
}
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);
+}
#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 *);
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 */
#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"
/* 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
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;
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
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,
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);
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));
+
+ 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);
+ return 0;
+}
+
static wq_item_status bgp_process_wq(struct work_queue *wq, void *data)
{
struct bgp_process_queue *pqnode = data;
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;
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);
}
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);
}
}
}
/* 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);
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 */
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)
#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;
#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;
*/
static inline void bgp_unlock_node(struct bgp_node *node)
{
+ bgp_delete_listnode(node);
route_unlock_node(bgp_node_to_rnode(node));
}
(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) {
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) {
int ret = 0;
bool found = false;
struct peer *peer;
- struct listnode *node, *nnode;
+
+ VTY_BGP_GR_DEFINE_LOOP_VARIABLE;
/* Clear all neighbors. */
/*
*/
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. */
}
}
+ 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 */
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)
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",
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)
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",
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;
}
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;
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);
}
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);
}
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;
}
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,
}
}
-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)
+static void bgp_show_neighnor_graceful_restart_rbit(struct vty *vty,
+ struct peer *p,
+ bool use_json,
+ json_object *json)
{
- struct bgp_filter *filter;
+ 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])
+ continue;
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)
+ || !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV))
+ continue;
+
+ 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)
+{
+ struct bgp_filter *filter;
struct peer_af *paf;
char orf_pfx_name[BUFSIZ];
int orf_pfx_count;
"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 {
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;
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,
}
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,
}
}
}
+ 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,
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],
eor_send_af_count ? ", "
: "",
get_afi_safi_str(afi,
- safi,
- false));
+ safi,
+ false));
eor_send_af_count++;
}
}
" 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();
}
}
+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,
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)
+ return;
+
+ 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,
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,
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);
+
+ enum global_mode 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:
+ 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,
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. */
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");
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");
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);
/* "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);
#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"
"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,
/* 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)
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;
+}
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);
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 */
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)
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();
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);
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;
}
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;
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;
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;
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) {
bgp_evpn_init(bgp);
bgp_pbr_init(bgp);
+
+ /*initilize global GR FSM */
+ bgp_global_gr_init(bgp);
return bgp;
}
struct listnode *node, *next;
struct vrf *vrf;
afi_t afi;
+ safi_t safi;
int i;
+ struct graceful_restart_info *gr_info;
assert(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)
+ continue;
+
+ BGP_TIMER_OFF(gr_info->t_select_deferral);
+ BGP_TIMER_OFF(gr_info->t_route_select);
+ 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");
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;
+ }
+}
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 */
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. */
#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)
#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];
/* 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;
#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;
(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) \
|| (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. */
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 {
#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 */
/*
/* 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
#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.
*/
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)
{
/* Hooks */
DECLARE_HOOK(peer_status_changed, (struct peer * peer), (peer))
+void peer_nsf_stop(struct peer *peer);
#endif /* _QUAGGA_BGPD_H */
yum install systemd-devel
+ For CentOS 7 and CentOS 8, the package will be built using python3
+ and requires additional python3 packages::
+
+ yum install python3-devel python3-sphinx
+
.. note::
For CentOS 8 you need to install ``platform-python-devel`` package
yum install platform-python-devel
- .. warning::
-
- ``python2-sphinx`` is not shipped for CentOS 8.
- Development reached the end of life for Python 2.
- We need to install it using ```pip``::
-
- pip2 install sphinx
If ``yum`` is not present on your system, use ``dnf`` instead.
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
Set explicitly network type for specified interface.
+OSPF6 route-map
+===============
+
+Usage of *ospfd6*'s route-map support.
+
+.. index:: set metric [+|-](0-4294967295)
+.. clicmd:: set metric [+|-](0-4294967295)
+
+ Set a metric for matched route when sending announcement. Use plus (+) sign
+ to add a metric value to an existing metric. Use minus (-) sign to
+ substract a metric value from an existing metric.
+
.. _redistribute-routes-to-ospf6:
Redistribute routes to OSPF6
Enable ospf on an interface and set associated area.
+OSPF route-map
+==============
+
+Usage of *ospfd*'s route-map support.
+
+.. index:: set metric [+|-](0-4294967295)
+.. clicmd:: set metric [+|-](0-4294967295)
+
+ Set a metric for matched route when sending announcement. Use plus (+) sign
+ to add a metric value to an existing metric. Use minus (-) sign to
+ substract a metric value from an existing metric.
+
.. _redistribute-routes-to-ospf:
Redistribution
have effect for vtysh) need to be manually updated in :file:`vtysh.conf`.
+.. index:: copy FILENAME running-config
+.. clicmd:: copy FILENAME running-config
+
+ Process and load a configuration file manually; each line in the
+ file is read and processed as if it were being typed (or piped) to
+ vtysh.
+
+
Pager usage
===========
Reset statistics related to the zebra code that interacts with the
optional Forwarding Plane Manager (FPM) component.
-.. index:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
-.. clicmd:: show nexthop-group [ID] [vrf NAME] [ip|ipv6]
-
- Display nexthop groups created by zebra.
+.. index:: show nexthop-group rib [ID] [vrf NAME] [singleton [ip|ip6]]
+.. clicmd:: show nexthop-group rib [ID] [vrf NAME]
+
+ Display nexthop groups created by zebra. The [vrf NAME] option
+ is only meaningful if you have started zebra with the --vrfwnetns
+ option as that nexthop groups are per namespace in linux.
+ If you specify singleton you would like to see the singleton
+ nexthop groups that do have an afi.
Router-id
#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 *);
masklen2ip(masklen, &mask);
return (masklen != IPV4_MAX_PREFIXLEN - 1) ?
- /* normal case */
- (hostaddr | ~mask.s_addr)
- :
- /* special case for /31 */
- (hostaddr ^ ~mask.s_addr);
+ /* normal case */
+ (hostaddr | ~mask.s_addr)
+ :
+ /* For prefix 31 return 255.255.255.255 (RFC3021) */
+ htonl(0xFFFFFFFF);
}
/* Utility function to convert ipv4 netmask to prefixes
extern void masklen2ip(const int, struct in_addr *);
/* given the address of a host on a network and the network mask length,
* calculate the broadcast address for that network;
- * special treatment for /31: returns the address of the other host
- * on the network by flipping the host bit */
+ * special treatment for /31 according to RFC3021 section 3.3 */
extern in_addr_t ipv4_broadcast_addr(in_addr_t hostaddr, int masklen);
extern int netmask_str2prefix_str(const char *, const char *, char *);
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;
+}
#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;
ZEBRA_MLAG_CLIENT_UNREGISTER,
ZEBRA_MLAG_FORWARD_MSG,
ZEBRA_ERROR,
+ ZEBRA_CLIENT_CAPABILITIES
} zebra_message_types_t;
enum zebra_error_types {
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 */
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 */
%endif
%endif
+# Check for python version - use python2.7 on CentOS 6, otherwise python3
+%if 0%{?rhel} && 0%{?rhel} < 7
+ %global use_python2 1
+%else
+ %global use_python2 0
+%endif
+
# If init system is systemd, then always enable watchfrr
%if "%{initsystem}" == "systemd"
%global with_watchfrr 1
BuildRequires: python27-devel
BuildRequires: python27-sphinx
%else
-%if 0%{?rhel} && 0%{?rhel} > 7
-BuildRequires: python2-devel
-#platform-python-devel is needed for /usr/bin/pathfix.py
-BuildRequires: platform-python-devel
-%else
+%if %{use_python2}
BuildRequires: python-devel >= 2.7
BuildRequires: python-sphinx
+%else
+BuildRequires: python3-devel
+BuildRequires: python3-sphinx
%endif
%endif
+%if 0%{?rhel} > 7
+#platform-python-devel is needed for /usr/bin/pathfix.py
+BuildRequires: platform-python-devel
+%endif
Requires: initscripts
%if %{with_pam}
BuildRequires: pam-devel
%package pythontools
Summary: python tools for frr
-%if 0%{?rhel} && 0%{?rhel} > 7
-BuildRequires: python2
-Requires: python2-ipaddress
+%if 0%{?rhel} && 0%{?rhel} < 7
+#python27 is available from ius community repo for RedHat/CentOS 6
+BuildRequires: python27
+Requires: python27-ipaddress
+%else
+%if %{use_python2}
+BuildRequires: python2
+Requires: python2-ipaddress
%else
-BuildRequires: python
-Requires: python-ipaddress
+BuildRequires: python3
+%endif
%endif
Group: System Environment/Daemons
make %{?_smp_mflags} MAKEINFO="makeinfo --no-split"
+%if %{use_python2}
+# Change frr-reload.py to use python2.7
+sed -e '1c #!/usr/bin/python2.7' -i %{zeb_src}/tools/frr-reload.py
+sed -e '1c #!/usr/bin/python2.7' -i %{zeb_src}/tools/generate_support_bundle.py
+%else
+# Change frr-reload.py to use python3
+sed -e '1c #!/usr/bin/python3' -i %{zeb_src}/tools/frr-reload.py
+sed -e '1c #!/usr/bin/python3' -i %{zeb_src}/tools/generate_support_bundle.py
+%endif
+
pushd doc
make info
popd
install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
install -d -m750 %{buildroot}%{rundir}
-%if 0%{?rhel} && 0%{?rhel} > 7
+%if 0%{?rhel} > 7 || 0%{?fedora} > 29
# avoid `ERROR: ambiguous python shebang in` errors
-pathfix.py -pni "%{__python2} %{py2_shbang_opts}" %{buildroot}/usr/lib/frr/*.py
-%py_byte_compile %{__python2} %{buildroot}/usr/lib/frr/*.py
+pathfix.py -pni "%{__python3} %{py3_shbang_opts}" %{buildroot}/usr/lib/frr/*.py
+%py_byte_compile %{__python3} %{buildroot}/usr/lib/frr/*.py
%endif
%pre
%files pythontools
%{_sbindir}/generate_support_bundle.py
+%{_sbindir}/frr-reload.py
+%if 0%{?rhel} > 7 || 0%{?fedora} > 29
+%{_sbindir}/__pycache__/*
+%else
%{_sbindir}/generate_support_bundle.pyc
%{_sbindir}/generate_support_bundle.pyo
%{_sbindir}/frr-reload.py
%{_sbindir}/frr-reload.pyc
%{_sbindir}/frr-reload.pyo
+%endif
%files devel
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]);
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 = {
oldFile = LOG_DIR + fileName
cpFileCmd = "cp " + oldFile + " " + oldFile + ".prev"
rmFileCmd = "rm -rf " + oldFile
- print "Making backup of " + oldFile
+ print("Making backup of " + oldFile)
os.system(cpFileCmd)
- print "Removing " + oldFile
+ print("Removing " + oldFile)
os.system(rmFileCmd)
return fileName
# Open the output file for this process
def openOutputFile(fileName):
crt_file_cmd = LOG_DIR + fileName
- print crt_file_cmd
+ print(crt_file_cmd)
try:
outputFile = open(crt_file_cmd, "w")
return outputFile
outputFile.write("########################################################\n")
outputFile.write('\n')
except:
- print "Writing to ouptut file Failed"
+ print("Writing to ouptut file Failed")
except subprocess.CalledProcessError as e:
dateTime = datetime.datetime.now()
outputFile.write(">>[" + str(dateTime) + "]" + cmd + "\n")
outputFile.write(e.output)
outputFile.write("########################################################\n")
outputFile.write('\n')
- print "Error:" + e.output
+ print("Error:" + e.output)
# Process the support bundle configuration file
if cmd_line[0] == "PROC_NAME":
outputFileName = createOutputFile(cmd_line[1])
if outputFileName:
- print outputFileName, "created for", cmd_line[1]
+ print(outputFileName, "created for", cmd_line[1])
elif cmd_line[0] == "CMD_LIST_START":
outputFile = openOutputFile(outputFileName)
if outputFile:
- print outputFileName, "opened"
+ print(outputFileName, "opened")
else:
- print outputFileName, "open failed"
- return FAIL
+ print(outputFileName, "open failed")
+ return FAIL
elif cmd_line[0] == "CMD_LIST_END":
if closeOutputFile(outputFile):
- print outputFileName, "closed"
+ print(outputFileName, "closed")
else:
- print outputFileName, "close failed"
+ print(outputFileName, "close failed")
else:
- print "Execute:" , cmd_line[0]
+ print("Execute:" , cmd_line[0])
executeCommand(cmd_line[0], outputFile)
# Main Function
lines = openConfFile(inputFile)
if not lines:
- print "File support_bundle_commands.conf not present in /etc/frr/ directory"
+ print("File support_bundle_commands.conf not present in /etc/frr/ directory")
else:
processConfFile(lines)
return vtysh_write_memory(self, vty, argc, argv);
}
+DEFUN (vtysh_copy_to_running,
+ vtysh_copy_to_running_cmd,
+ "copy FILENAME running-config",
+ "Apply a configuration file\n"
+ "Configuration file to read\n"
+ "Apply to current configuration\n")
+{
+ int ret;
+ const char *fname = argv[1]->arg;
+
+ ret = vtysh_read_config(fname);
+
+ /* Return to enable mode - the 'read_config' api leaves us up a level */
+ vtysh_execute_no_pager("enable");
+
+ return ret;
+}
+
DEFUN (vtysh_terminal_paginate,
vtysh_terminal_paginate_cmd,
"[no] terminal paginate",
install_element(INTERFACE_NODE, &vtysh_link_params_cmd);
install_element(ENABLE_NODE, &vtysh_show_running_config_cmd);
install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd);
+ install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd);
install_element(CONFIG_NODE, &vtysh_vrf_cmd);
install_element(VRF_NODE, &vtysh_vrf_netns_cmd);
if (IS_ZEBRA_DEBUG_MLAG)
vty_out(vty, " Zebra mlag debugging is on\n");
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
- vty_out(vty, "Zebra detailed nexthop debugging is on\n");
+ vty_out(vty, " Zebra detailed nexthop debugging is on\n");
else if (IS_ZEBRA_DEBUG_NHG)
- vty_out(vty, "Zebra nexthop debugging is on\n");
+ vty_out(vty, " Zebra nexthop debugging is on\n");
hook_call(zebra_debug_show_debugging, vty);
return CMD_SUCCESS;
write++;
}
+ if (CHECK_FLAG(zebra_debug_nexthop, ZEBRA_DEBUG_NHG_DETAILED)) {
+ vty_out(vty, "debug zebra nexthop detail\n");
+ write++;
+ } else if (CHECK_FLAG(zebra_debug_nexthop, ZEBRA_DEBUG_NHG)) {
+ vty_out(vty, "debug zebra nexthop\n");
+ write++;
+ }
+
return write;
}
nhm = NLMSG_DATA(h);
+ if (ns_id)
+ vrf_id = ns_id;
+
if (startup && h->nlmsg_type != RTM_NEWNEXTHOP)
return 0;
return -1;
} else if (h->nlmsg_type == RTM_DELNEXTHOP)
- zebra_nhg_kernel_del(id);
+ zebra_nhg_kernel_del(id, vrf_id);
return 0;
}
api_nh = &api.nexthops[i];
ifindex_t ifindex = 0;
+ nexthop = NULL;
+
if (IS_ZEBRA_DEBUG_RECV)
zlog_debug("nh type %d", api_nh->type);
return nhg_connected_tree_first(head);
}
-void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
- struct nhg_hash_entry *depend)
+struct nhg_hash_entry *
+nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *depend)
{
struct nhg_connected lookup = {};
struct nhg_connected *remove = NULL;
+ struct nhg_hash_entry *removed_nhe;
lookup.nhe = depend;
/* Lookup to find the element, then remove it */
remove = nhg_connected_tree_find(head, &lookup);
- remove = nhg_connected_tree_del(head, remove);
-
if (remove)
+ /* Re-returning here just in case this API changes..
+ * the _del list api's are a bit undefined at the moment.
+ *
+ * So hopefully returning here will make it fail if the api
+ * changes to something different than currently expected.
+ */
+ remove = nhg_connected_tree_del(head, remove);
+
+ /* If the entry was sucessfully removed, free the 'connected` struct */
+ if (remove) {
+ removed_nhe = remove->nhe;
nhg_connected_free(remove);
+ return removed_nhe;
+ }
+
+ return NULL;
}
-void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
- struct nhg_hash_entry *depend)
+/* Assuming UNIQUE RB tree. If this changes, assumptions here about
+ * insertion need to change.
+ */
+struct nhg_hash_entry *
+nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *depend)
{
struct nhg_connected *new = NULL;
new = nhg_connected_new(depend);
- if (new)
- nhg_connected_tree_add(head, new);
+ /* On success, NULL will be returned from the
+ * RB code.
+ */
+ if (new && (nhg_connected_tree_add(head, new) == NULL))
+ return NULL;
+
+ /* If it wasn't successful, it must be a duplicate. We enforce the
+ * unique property for the `nhg_connected` tree.
+ */
+ nhg_connected_free(new);
+
+ return depend;
}
static void
struct interface *ifp = NULL;
ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex,
- nhe->vrf_id);
+ nhe->nhg->nexthop->vrf_id);
if (ifp)
zebra_nhg_set_if(nhe, ifp);
else
flog_err(
EC_ZEBRA_IF_LOOKUP_FAILED,
"Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u",
- nhe->nhg->nexthop->ifindex, nhe->vrf_id,
- nhe->id);
+ nhe->nhg->nexthop->ifindex,
+ nhe->nhg->nexthop->vrf_id, nhe->id);
}
}
resolved_ng.nexthop = nh;
depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
- depends_add(nhg_depends, depend);
+
+ if (depend)
+ depends_add(nhg_depends, depend);
}
static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id,
lookup.type = type ? type : ZEBRA_ROUTE_NHG;
lookup.nhg = nhg;
+ lookup.vrf_id = vrf_id;
if (lookup.nhg->nexthop->next) {
/* Groups can have all vrfs and AF's in them */
lookup.afi = AFI_UNSPEC;
- lookup.vrf_id = VRF_DEFAULT;
} else {
switch (lookup.nhg->nexthop->type) {
case (NEXTHOP_TYPE_IFINDEX):
lookup.afi = AFI_IP6;
break;
}
-
- lookup.vrf_id = vrf_id;
}
if (id)
{
struct nhg_hash_entry *nhe = NULL;
struct nexthop_group nhg = {};
+ vrf_id_t vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nh->vrf_id;
nexthop_group_add_sorted(&nhg, nh);
- zebra_nhg_find(&nhe, id, &nhg, NULL, nh->vrf_id, afi, type);
+ zebra_nhg_find(&nhe, id, &nhg, NULL, vrf_id, afi, type);
return nhe;
}
}
/* Kernel-side, received delete message */
-int zebra_nhg_kernel_del(uint32_t id)
+int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
{
struct nhg_ctx *ctx = NULL;
- ctx = nhg_ctx_init(id, NULL, NULL, 0, 0, 0, 0);
+ ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0);
nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
static void depends_add(struct nhg_connected_tree_head *head,
struct nhg_hash_entry *depend)
{
- nhg_connected_tree_add_nhe(head, depend);
- zebra_nhg_increment_ref(depend);
+ /* If NULL is returned, it was successfully added and
+ * needs to have its refcnt incremented.
+ *
+ * Else the NHE is already present in the tree and doesn't
+ * need to increment the refcnt.
+ */
+ if (nhg_connected_tree_add_nhe(head, depend) == NULL)
+ zebra_nhg_increment_ref(depend);
}
static struct nhg_hash_entry *
zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
{
struct nhg_hash_entry *nhe = NULL;
+ vrf_id_t vrf_id;
+
+ /*
+ * CLANG SA is complaining that nexthop may be NULL
+ * Make it happy but this is ridonc
+ */
+ assert(nhg->nexthop);
+ vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
if (!(nhg && nhg->nexthop)) {
flog_err(EC_ZEBRA_TABLE_LOOKUP_FAILED,
return NULL;
}
- zebra_nhg_find(&nhe, id, nhg, NULL, nhg->nexthop->vrf_id, rt_afi, 0);
+ zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
return nhe;
}
vrf_id_t vrf_id, afi_t afi, int type,
int startup);
/* Del via kernel */
-extern int zebra_nhg_kernel_del(uint32_t id);
+extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
/* Find via route creation */
extern struct nhg_hash_entry *
nhg_connected_tree_is_empty(const struct nhg_connected_tree_head *head);
extern struct nhg_connected *
nhg_connected_tree_root(struct nhg_connected_tree_head *head);
-extern void nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
- struct nhg_hash_entry *nhe);
-extern void nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
- struct nhg_hash_entry *nhe);
+
+/* I realize _add/_del returns are backwords.
+ *
+ * Currently the list APIs are not standardized for what happens in
+ * the _del() function when the item isn't present.
+ *
+ * We are choosing to return NULL if not found in the _del case for now.
+ */
+
+/* Delete NHE from the tree. On success, return the NHE, otherwise NULL. */
+extern struct nhg_hash_entry *
+nhg_connected_tree_del_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *nhe);
+/* ADD NHE to the tree. On success, return NULL, otherwise return the NHE. */
+extern struct nhg_hash_entry *
+nhg_connected_tree_add_nhe(struct nhg_connected_tree_head *head,
+ struct nhg_hash_entry *nhe);
#endif /* __ZEBRA_NHG_PRIVATE_H__ */
int *sock = data;
if (ipset->sock == *sock) {
- hook_call(zebra_pbr_ipset_update, 0, ipset);
- hash_release(zrouter.ipset_hash, ipset);
+ if (hash_release(zrouter.ipset_hash, ipset))
+ zebra_pbr_ipset_free(ipset);
+ else
+ hook_call(zebra_pbr_ipset_update, 0, ipset);
}
}
int *sock = data;
if (ipset->sock == *sock) {
- hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
- hash_release(zrouter.ipset_entry_hash, ipset);
+ if (hash_release(zrouter.ipset_entry_hash, ipset))
+ zebra_pbr_ipset_entry_free(ipset);
+ else
+ hook_call(zebra_pbr_ipset_entry_update, 0, ipset);
}
}
int *sock = data;
if (iptable->sock == *sock) {
- hook_call(zebra_pbr_iptable_update, 0, iptable);
- hash_release(zrouter.iptable_hash, iptable);
+ if (hash_release(zrouter.iptable_hash, iptable))
+ zebra_pbr_iptable_free(iptable);
+ else
+ hook_call(zebra_pbr_iptable_update, 0, iptable);
}
}
DEFPY (show_nexthop_group,
show_nexthop_group_cmd,
- "show nexthop-group rib <(0-4294967295)$id|[<ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
+ "show nexthop-group rib <(0-4294967295)$id|[singleton <ip$v4|ipv6$v6>] [vrf <NAME$vrf_name|all$vrf_all>]>",
SHOW_STR
"Show Nexthop Groups\n"
"RIB information\n"
"Nexthop Group ID\n"
+ "Show Singleton Nexthop-Groups\n"
IP_STR
IP6_STR
VRF_FULL_CMD_HELP_STR)
{
struct zebra_vrf *zvrf = NULL;
- afi_t afi = 0;
+ afi_t afi = AFI_UNSPEC;
if (id)
return show_nexthop_group_id_cmd_helper(vty, id);
else if (v6)
afi = AFI_IP6;
+ if (vrf_is_backend_netns() && (vrf_name || vrf_all)) {
+ vty_out(vty, "VRF subcommand does not make any sense in l3mdev based vrf's");
+ return CMD_WARNING;
+ }
+
if (vrf_all) {
struct vrf *vrf;