From 05bd726cfeeb9f8207fbc85082b98507bcecda41 Mon Sep 17 00:00:00 2001 From: vivek Date: Sat, 19 Sep 2020 14:22:17 -0700 Subject: [PATCH] bgpd: Implement BGP-wide configuration for graceful shutdown 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 --- bgpd/bgp_vty.c | 113 +++++++++++++++++++++++++++++++++++++++++------ bgpd/bgpd.h | 7 ++- doc/user/bgp.rst | 26 +++++++++++ 3 files changed, 132 insertions(+), 14 deletions(-) diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 505f743e29..005fad1409 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -2805,6 +2805,69 @@ 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, @@ -2812,14 +2875,21 @@ DEFUN (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; @@ -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; @@ -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) @@ -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)) { @@ -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, @@ -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, @@ -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); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 6293c4136c..e282e461df 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -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 }; @@ -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); diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 764428cb0a..723cb41f26 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -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 -- 2.39.5