Skip to content

Commit

Permalink
bgpd: Implement BGP-wide configuration for graceful shutdown
Browse files Browse the repository at this point in the history
Add support for a BGP-wide setting to enter and exit graceful shutdown.
This will apply to all BGP peers across all BGP instances. Per-instance
configuration is disallowed if the BGP-wide setting is in effect.

Signed-off-by: Vivek Venkatraman <vivek@nvidia.com>
  • Loading branch information
vivek-cumulus committed Sep 20, 2020
1 parent 637e5ba commit 05bd726
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 14 deletions.
113 changes: 100 additions & 13 deletions bgpd/bgp_vty.c
Original file line number Diff line number Diff line change
Expand Up @@ -2805,21 +2805,91 @@ DEFUN (no_bgp_graceful_restart_rib_stale_time,
return CMD_SUCCESS;
}

static inline void bgp_initiate_graceful_shut_unshut(struct vty *vty,
struct bgp *bgp)
{
bgp_static_redo_import_check(bgp);
bgp_redistribute_redo(bgp);
bgp_clear_star_soft_out(vty, bgp->name);
bgp_clear_star_soft_in(vty, bgp->name);
}

static int bgp_global_graceful_shutdown_config_vty(struct vty *vty)
{
struct listnode *node, *nnode;
struct bgp *bgp;
bool vrf_cfg = false;

if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
return CMD_SUCCESS;

/* See if graceful-shutdown is set per-vrf and warn user to delete */
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
vty_out(vty,
"%% graceful-shutdown configuration found in vrf %s\n",
bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT ?
VRF_DEFAULT_NAME : bgp->name);
vrf_cfg = true;
}
}

if (vrf_cfg) {
vty_out(vty,
"%%Failed: global graceful-shutdown not permitted\n");
return CMD_WARNING;
}

/* Set flag globally */
SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN);

/* Initiate processing for all BGP instances. */
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
bgp_initiate_graceful_shut_unshut(vty, bgp);

return CMD_SUCCESS;
}

static int bgp_global_graceful_shutdown_deconfig_vty(struct vty *vty)
{
struct listnode *node, *nnode;
struct bgp *bgp;

if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
return CMD_SUCCESS;

/* Unset flag globally */
UNSET_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN);

/* Initiate processing for all BGP instances. */
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp))
bgp_initiate_graceful_shut_unshut(vty, bgp);

return CMD_SUCCESS;
}

/* "bgp graceful-shutdown" configuration */
DEFUN (bgp_graceful_shutdown,
bgp_graceful_shutdown_cmd,
"bgp graceful-shutdown",
BGP_STR
"Graceful shutdown parameters\n")
{
if (vty->node == CONFIG_NODE)
return bgp_global_graceful_shutdown_config_vty(vty);

VTY_DECLVAR_CONTEXT(bgp, bgp);

/* if configured globally, per-instance config is not allowed */
if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) {
vty_out(vty,
"%%Failed: per-vrf graceful-shutdown config not permitted with global graceful-shutdown\n");
return CMD_WARNING_CONFIG_FAILED;
}

if (!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
SET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN);
bgp_static_redo_import_check(bgp);
bgp_redistribute_redo(bgp);
bgp_clear_star_soft_out(vty, bgp->name);
bgp_clear_star_soft_in(vty, bgp->name);
bgp_initiate_graceful_shut_unshut(vty, bgp);
}

return CMD_SUCCESS;
Expand All @@ -2832,14 +2902,21 @@ DEFUN (no_bgp_graceful_shutdown,
BGP_STR
"Graceful shutdown parameters\n")
{
if (vty->node == CONFIG_NODE)
return bgp_global_graceful_shutdown_deconfig_vty(vty);

VTY_DECLVAR_CONTEXT(bgp, bgp);

/* If configured globally, cannot remove from one bgp instance */
if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)) {
vty_out(vty,
"%%Failed: bgp graceful-shutdown configured globally. Delete per-vrf not permitted\n");
return CMD_WARNING_CONFIG_FAILED;
}

if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
UNSET_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN);
bgp_static_redo_import_check(bgp);
bgp_redistribute_redo(bgp);
bgp_clear_star_soft_out(vty, bgp->name);
bgp_clear_star_soft_in(vty, bgp->name);
bgp_initiate_graceful_shut_unshut(vty, bgp);
}

return CMD_SUCCESS;
Expand Down Expand Up @@ -6386,7 +6463,6 @@ DEFUN (no_bgp_set_route_map_delay_timer,
return CMD_SUCCESS;
}


/* neighbor interface */
static int peer_interface_vty(struct vty *vty, const char *ip_str,
const char *str)
Expand Down Expand Up @@ -15528,6 +15604,9 @@ int bgp_config_write(struct vty *vty)
vty_out(vty, "\n");
}

if (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
vty_out(vty, "bgp graceful-shutdown\n");

/* BGP configuration. */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {

Expand Down Expand Up @@ -15679,6 +15758,14 @@ int bgp_config_write(struct vty *vty)
/* coalesce time */
bgp_config_write_coalesce_time(vty, bgp);

/* BGP per-instance graceful-shutdown */
/* BGP-wide settings and per-instance settings are mutually
* exclusive.
*/
if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN))
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
vty_out(vty, " bgp graceful-shutdown\n");

/* BGP graceful-restart. */
if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
vty_out(vty,
Expand All @@ -15700,10 +15787,6 @@ int bgp_config_write(struct vty *vty)
if (bgp_global_gr_mode_get(bgp) == GLOBAL_DISABLE)
vty_out(vty, " bgp graceful-restart-disable\n");

/* BGP graceful-shutdown */
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
vty_out(vty, " bgp graceful-shutdown\n");

/* BGP graceful-restart Preserve State F bit. */
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD))
vty_out(vty,
Expand Down Expand Up @@ -16046,6 +16129,10 @@ void bgp_vty_init(void)
install_element(CONFIG_NODE, &bgp_global_update_delay_cmd);
install_element(CONFIG_NODE, &no_bgp_global_update_delay_cmd);

/* global bgp graceful-shutdown command */
install_element(CONFIG_NODE, &bgp_graceful_shutdown_cmd);
install_element(CONFIG_NODE, &no_bgp_graceful_shutdown_cmd);

/* Dummy commands (Currently not supported) */
install_element(BGP_NODE, &no_synchronization_cmd);
install_element(BGP_NODE, &no_auto_summary_cmd);
Expand Down
7 changes: 6 additions & 1 deletion bgpd/bgpd.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ struct bgp_master {
uint16_t v_update_delay;
uint16_t v_establish_wait;

uint32_t flags;
#define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0)

bool terminating; /* global flag that sigint terminate seen */
QOBJ_FIELDS
};
Expand Down Expand Up @@ -2159,7 +2162,9 @@ static inline void bgp_vrf_unlink(struct bgp *bgp, struct vrf *vrf)

static inline bool bgp_in_graceful_shutdown(struct bgp *bgp)
{
return !!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN);
/* True if either set for this instance or globally */
return (!!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN) ||
!!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN));
}

extern void bgp_unset_redist_vrf_bitmaps(struct bgp *, vrf_id_t);
Expand Down
26 changes: 26 additions & 0 deletions doc/user/bgp.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2732,6 +2732,32 @@ The following are available in the ``router bgp`` mode:
at a time in a loop. This setting controls how many iterations the loop runs
for. As with write-quanta, it is best to leave this setting on the default.

The following command is available in ``config`` mode as well as in the
``router bgp`` mode:

.. index:: bgp graceful-shutdown
.. clicmd:: bgp graceful-shutdown

The purpose of this command is to initiate BGP Graceful Shutdown which
is described in :rfc:`8326`. The use case for this is to minimize or
eliminate the amount of traffic loss in a network when a planned
maintenance activity such as software upgrade or hardware replacement
is to be performed on a router. The feature works by re-announcing
routes to eBGP peers with the GRACEFUL_SHUTDOWN community included.
Peers are then expected to treat such paths with the lowest preference.
This happens automatically on a receiver running FRR; with other
routing protocol stacks, an inbound policy may have to be configured.
In FRR, triggering graceful shutdown also results in announcing a
LOCAL_PREF of 0 to iBGP peers.

Graceful shutdown can be configured per BGP instance or globally for
all of BGP. These two options are mutually exclusive. The no form of
the command causes graceful shutdown to be stopped, and routes will
be re-announced without the GRACEFUL_SHUTDOWN community and/or with
the usual LOCAL_PREF value. Note that if this option is saved to
the startup configuration, graceful shutdown will remain in effect
across restarts of *bgpd* and will need to be explicitly disabled.

.. _bgp-displaying-bgp-information:

Displaying BGP Information
Expand Down

0 comments on commit 05bd726

Please sign in to comment.