Merge pull request #7138 from vivek-cumulus/bgp_global_gshut

BGP-wide graceful shutdown
This commit is contained in:
Santosh P K 2020-09-22 11:16:03 +05:30 committed by GitHub
commit f1b8efb42c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 676 additions and 24 deletions

View File

@ -954,7 +954,7 @@ struct attr *bgp_attr_aggregate_intern(
/* If we are not shutting down ourselves and we are
* aggregating a route that contains the GSHUT community we
* need to remove that community when creating the aggregate */
if (!CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)
if (!bgp_in_graceful_shutdown(bgp)
&& community_include(community, gshut)) {
community_del_val(community, &gshut);
}
@ -973,7 +973,7 @@ struct attr *bgp_attr_aggregate_intern(
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES);
}
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
if (bgp_in_graceful_shutdown(bgp))
bgp_attr_add_gshut_community(&attr);
attr.label_index = BGP_INVALID_LABEL_INDEX;
@ -1016,13 +1016,13 @@ struct attr *bgp_attr_aggregate_intern(
return NULL;
}
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
if (bgp_in_graceful_shutdown(bgp))
bgp_attr_add_gshut_community(&attr_tmp);
new = bgp_attr_intern(&attr_tmp);
} else {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
if (bgp_in_graceful_shutdown(bgp))
bgp_attr_add_gshut_community(&attr);
new = bgp_attr_intern(&attr);

View File

@ -2021,7 +2021,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
if (aspath_check_as_zero(attr->aspath))
return false;
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) {
if (bgp_in_graceful_shutdown(bgp)) {
if (peer->sort == BGP_PEER_IBGP
|| peer->sort == BGP_PEER_CONFED) {
attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
@ -3579,8 +3579,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* If graceful-shutdown is configured then add the GSHUT
* community to all paths received from eBGP peers */
} else if (CHECK_FLAG(peer->bgp->flags,
BGP_FLAG_GRACEFUL_SHUTDOWN))
} else if (bgp_in_graceful_shutdown(peer->bgp))
bgp_attr_add_gshut_community(&new_attr);
}
@ -5119,13 +5118,13 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
return;
}
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
if (bgp_in_graceful_shutdown(bgp))
bgp_attr_add_gshut_community(&attr_tmp);
attr_new = bgp_attr_intern(&attr_tmp);
} else {
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
if (bgp_in_graceful_shutdown(bgp))
bgp_attr_add_gshut_community(&attr);
attr_new = bgp_attr_intern(&attr);
@ -7366,7 +7365,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
}
}
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
if (bgp_in_graceful_shutdown(bgp))
bgp_attr_add_gshut_community(&attr_new);
bn = bgp_afi_node_get(bgp->rib[afi][SAFI_UNICAST], afi,

View File

@ -868,7 +868,7 @@ void subgroup_default_originate(struct update_subgroup *subgrp, int withdraw)
}
/* Advertise the default route */
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
if (bgp_in_graceful_shutdown(bgp))
bgp_attr_add_gshut_community(new_attr);
SET_FLAG(subgrp->sflags,

View File

@ -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);

View File

@ -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
};
@ -2157,6 +2160,13 @@ static inline void bgp_vrf_unlink(struct bgp *bgp, struct vrf *vrf)
bgp->vrf_id = VRF_UNKNOWN;
}
static inline bool bgp_in_graceful_shutdown(struct bgp *bgp)
{
/* 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);
/* For benefit of rfapi */

View File

@ -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

View File

View File

@ -0,0 +1,12 @@
{
"prefix":"13.1.1.1\/32",
"paths":[
{
"origin":"IGP",
"metric":0,
"locPrf":100,
"valid":true
}
]
}

View File

@ -0,0 +1,17 @@
{
"prefix":"13.1.1.1\/32",
"paths":[
{
"origin":"IGP",
"metric":0,
"locPrf":0,
"valid":true,
"community":{
"string":"graceful-shutdown",
"list":[
"gracefulShutdown"
]
}
}
]
}

View File

@ -0,0 +1,10 @@
! exit1
router bgp 65001
no bgp ebgp-requires-policy
no bgp network import-check
neighbor 192.168.255.1 remote-as 65001
neighbor 192.168.255.1 timers connect 10
address-family ipv4 unicast
network 11.1.1.1/32
exit-address-family
!

View File

@ -0,0 +1,9 @@
! exit1
interface lo
ip address 172.16.255.254/32
!
interface r1-eth0
ip address 192.168.255.2/30
!
ip forwarding
!

View File

@ -0,0 +1,15 @@
{
"ipv4Unicast":{
"peers":{
"192.168.254.2":{
"remoteAs":65003,
"state":"Established"
},
"192.168.255.2":{
"remoteAs":65001,
"state":"Established"
}
},
"totalPeers":2
}
}

View File

@ -0,0 +1,15 @@
{
"ipv4Unicast":{
"peers":{
"192.168.252.2":{
"remoteAs":65005,
"state":"Established"
},
"192.168.253.2":{
"remoteAs":65004,
"state":"Established"
}
},
"totalPeers":2
}
}

View File

@ -0,0 +1,20 @@
!
router bgp 65001
no bgp ebgp-requires-policy
timers bgp 3 9
neighbor 192.168.255.2 remote-as 65001
neighbor 192.168.254.2 remote-as 65003
neighbor 192.168.255.2 timers connect 10
neighbor 192.168.254.2 timers connect 10
address-family ipv4 unicast
redistribute connected
exit-address-family
!
router bgp 65001 vrf vrf1
no bgp ebgp-requires-policy
timers bgp 3 9
neighbor 192.168.253.2 remote-as 65004
neighbor 192.168.253.2 timers connect 10
neighbor 192.168.252.2 remote-as 65005
neighbor 192.168.252.2 timers connect 10
!

View File

@ -0,0 +1,13 @@
! spine
interface r2-eth0
ip address 192.168.255.1/30
!
interface r2-eth1
ip address 192.168.254.1/30
!
interface r2-eth2 vrf vrf1
ip address 192.168.253.1/30
!
interface r2-eth3 vrf vrf1
ip address 192.168.252.1/30
!

View File

@ -0,0 +1,9 @@
{
"prefix":"11.1.1.1\/32",
"paths":[
{
"origin":"IGP",
"valid":true
}
]
}

View File

@ -0,0 +1,16 @@
{
"prefix":"11.1.1.1\/32",
"paths":[
{
"origin":"IGP",
"locPrf":0,
"valid":true,
"community":{
"string":"graceful-shutdown",
"list":[
"gracefulShutdown"
]
}
}
]
}

View File

@ -0,0 +1,11 @@
!
router bgp 65003
no bgp ebgp-requires-policy
no bgp network import-check
timers bgp 3 9
neighbor 192.168.254.1 remote-as 65001
neighbor 192.168.254.1 timers connect 10
address-family ipv4 unicast
network 13.1.1.1/32
exit-address-family
!

View File

@ -0,0 +1,9 @@
! exit2
interface lo
ip address 172.16.254.254/32
!
interface r3-eth0
ip address 192.168.254.2/30
!
ip forwarding
!

View File

@ -0,0 +1,11 @@
!
router bgp 65004
no bgp ebgp-requires-policy
no bgp network import-check
timers bgp 3 9
neighbor 192.168.253.1 remote-as 65001
neighbor 192.168.253.1 timers connect 10
address-family ipv4 unicast
network 14.1.1.1/32
exit-address-family
!

View File

@ -0,0 +1,9 @@
! exit2
interface lo
ip address 172.16.253.254/32
!
interface r4-eth0
ip address 192.168.253.2/30
!
ip forwarding
!

View File

@ -0,0 +1,9 @@
{
"prefix":"14.1.1.1\/32",
"paths":[
{
"origin":"IGP",
"valid":true
}
]
}

View File

@ -0,0 +1,16 @@
{
"prefix":"14.1.1.1\/32",
"paths":[
{
"origin":"IGP",
"locPrf":0,
"valid":true,
"community":{
"string":"graceful-shutdown",
"list":[
"gracefulShutdown"
]
}
}
]
}

View File

@ -0,0 +1,7 @@
!
router bgp 65005
no bgp ebgp-requires-policy
timers bgp 3 9
neighbor 192.168.252.1 remote-as 65001
neighbor 192.168.252.1 timers connect 10
!

View File

@ -0,0 +1,9 @@
! exit1
interface lo
ip address 172.16.252.254/32
!
interface r5-eth0
ip address 192.168.252.2/30
!
ip forwarding
!

View File

@ -0,0 +1,313 @@
#!/usr/bin/env python
#
# test_bgp_gshut.py
# Part of NetDEF Topology Tests
#
# Copyright (c) 2020 by
# Vivek Venkatraman <vivek@nvidia.com>
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""
Test the ability to initiate and stop BGP graceful shutdown.
Test both the vrf-specific and global configuration and operation.
r1
|
r2----r3
| \
| \
r4 r5
r2 is UUT and peers with r1 and r3 in default bgp instance and
with r4 and r5 in vrf vrf1.
r1-r2 peering is iBGP and the other peerings are eBGP.
Check r2 initial convergence in default table
Define update-delay with max-delay in the default bgp instance on r2
Shutdown peering on r1 toward r2 so that delay timers can be exercised
Clear bgp neighbors on r2 and then check for the 'in progress' indicator
Check that r2 only installs route learned from r4 after the max-delay timer expires
Define update-delay with max-delay and estabish-wait and check json output showing set
Clear neighbors on r2 and check that r3 installs route from r4 after establish-wait time
Remove update-delay timer on r2 to verify that it goes back to normal behavior
Clear neighbors on r2 and check that route install time on r2 does not delay
Define global bgp update-delay with max-delay and establish-wait on r2
Check that r2 default instance and vrf1 have the max-delay and establish set
Clear neighbors on r2 and check route-install time is after the establish-wait timer
Note that the keepalive/hold times were changed to 3/9 and the connect retry timer
to 10 to improve the odds the convergence timing in this test case is useful in the
event of packet loss.
"""
import os
import re
import sys
import json
import time
import pytest
import functools
import platform
from functools import partial
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
from mininet.topo import Topo
class TemplateTopo(Topo):
def build(self, *_args, **_opts):
tgen = get_topogen(self)
for routern in range(1, 6):
tgen.add_router("r{}".format(routern))
switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
switch = tgen.add_switch("s2")
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
switch = tgen.add_switch("s3")
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r4"])
switch = tgen.add_switch("s4")
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r5"])
def _run_cmd_and_check(router, cmd, results_file, retries=100, intvl=0.5):
json_file = "{}/{}".format(CWD, results_file)
expected = json.loads(open(json_file).read())
test_func = partial(topotest.router_json_cmp, router, cmd, expected)
return topotest.run_and_expect(test_func, None, retries, intvl)
def setup_module(mod):
tgen = Topogen(TemplateTopo, mod.__name__)
tgen.start_topology()
router_list = tgen.routers()
krel = platform.release()
if topotest.version_cmp(krel, "4.5") < 0:
tgen.errors = "Linux kernel version of at least 4.5 needed for bgp-gshut tests"
pytest.skip(tgen.errors)
# Configure vrf and its slaves in the kernel on r2
r2 = tgen.gears["r2"]
r2.run("ip link add vrf1 type vrf table 1000")
r2.run("ip link set vrf1 up")
r2.run("ip link set r2-eth2 master vrf1")
r2.run("ip link set r2-eth3 master vrf1")
# Load FRR config and initialize all routers
for i, (rname, router) in enumerate(router_list.items(), 1):
router.load_config(
TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
)
tgen.start_router()
# Basic peering test to see if things are ok
_, result = _run_cmd_and_check(r2, 'show ip bgp summary json', 'r2/bgp_sum_1.json')
assertmsg = 'R2: Basic sanity test after init failed -- global peerings not up'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r2, 'show ip bgp vrf vrf1 summary json', 'r2/bgp_sum_2.json')
assertmsg = 'R2: Basic sanity test after init failed -- VRF peerings not up'
assert result is None, assertmsg
def teardown_module(mod):
tgen = get_topogen()
tgen.stop_topology()
def test_bgp_gshut():
tgen = get_topogen()
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
r1 = tgen.gears["r1"]
r2 = tgen.gears["r2"]
r3 = tgen.gears["r3"]
r4 = tgen.gears["r4"]
r5 = tgen.gears["r5"]
# Verify initial route states
logger.info('\nVerify initial route states')
_, result = _run_cmd_and_check(r1, 'show ip bgp 13.1.1.1/32 json', 'r1/bgp_route_1.json')
assertmsg = 'R1: Route 13.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r3, 'show ip bgp 11.1.1.1/32 json', 'r3/bgp_route_1.json')
assertmsg = 'R3: Route 11.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r5, 'show ip bgp 14.1.1.1/32 json', 'r5/bgp_route_1.json')
assertmsg = 'R5: Route 14.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
logger.info('\nInitial route states are as expected')
#"Test #1: Enable BGP-wide graceful-shutdown on R2 and check routes on peers"
logger.info('\nTest #1: Enable BGP-wide graceful-shutdown on R2 and check routes on peers')
r2.vtysh_cmd(
"""
configure terminal
bgp graceful-shutdown
"""
)
# R1, R3 and R5 should see routes from R2 with GSHUT. In addition,
# R1 should see LOCAL_PREF of 0
_, result = _run_cmd_and_check(r1, 'show ip bgp 13.1.1.1/32 json', 'r1/bgp_route_2.json')
assertmsg = 'R1: Route 13.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r3, 'show ip bgp 11.1.1.1/32 json', 'r3/bgp_route_2.json')
assertmsg = 'R3: Route 11.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r5, 'show ip bgp 14.1.1.1/32 json', 'r5/bgp_route_2.json')
assertmsg = 'R5: Route 14.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
logger.info('\nTest #1: Successful, routes have GSHUT and/or LPREF of 0 as expected')
#"Test #2: Turn off BGP-wide graceful-shutdown on R2 and check routes on peers"
logger.info('\nTest #2: Turn off BGP-wide graceful-shutdown on R2 and check routes on peers')
r2.vtysh_cmd(
"""
configure terminal
no bgp graceful-shutdown
"""
)
# R1, R3 and R5 should see routes from R2 with their original attributes
_, result = _run_cmd_and_check(r1, 'show ip bgp 13.1.1.1/32 json', 'r1/bgp_route_1.json')
assertmsg = 'R1: Route 13.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r3, 'show ip bgp 11.1.1.1/32 json', 'r3/bgp_route_1.json')
assertmsg = 'R3: Route 11.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r5, 'show ip bgp 14.1.1.1/32 json', 'r5/bgp_route_1.json')
assertmsg = 'R5: Route 14.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
logger.info('\nTest #2: Successful, routes have their original attributes with default LPREF and without GSHUT')
#"Test #3: Enable graceful-shutdown on R2 only in VRF1 and check routes on peers"
logger.info('\nTest #3: Enable graceful-shutdown on R2 only in VRF1 and check routes on peers')
r2.vtysh_cmd(
"""
configure terminal
router bgp 65001 vrf vrf1
bgp graceful-shutdown
"""
)
# R1 and R3 should see no change to their routes
_, result = _run_cmd_and_check(r1, 'show ip bgp 13.1.1.1/32 json', 'r1/bgp_route_1.json')
assertmsg = 'R1: Route 13.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r3, 'show ip bgp 11.1.1.1/32 json', 'r3/bgp_route_1.json')
assertmsg = 'R3: Route 11.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
# R5 should see routes from R2 with GSHUT.
_, result = _run_cmd_and_check(r5, 'show ip bgp 14.1.1.1/32 json', 'r5/bgp_route_2.json')
assertmsg = 'R5: Route 14.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
logger.info('\nTest #3: Successful, only VRF peers like R5 see routes with GSHUT')
#"Test #4: Try to enable BGP-wide graceful-shutdown on R2 while it is configured in VRF1"
logger.info('\nTest #4: Try to enable BGP-wide graceful-shutdown on R2 while it is configured in VRF1')
ret = r2.vtysh_cmd(
"""
configure terminal
bgp graceful-shutdown
"""
)
# This should fail
assertmsg = 'R2: BGP-wide graceful-shutdown config not rejected even though it is enabled in VRF1'
assert re.search("global graceful-shutdown not permitted", ret) is not None, assertmsg
logger.info('\nTest #4: Successful, BGP-wide graceful-shutdown rejected as it is enabled in VRF')
#"Test #5: Turn off graceful-shutdown on R2 in VRF1 and check routes on peers"
logger.info('\nTest #5: Turn off graceful-shutdown on R2 in VRF1 and check routes on peers')
r2.vtysh_cmd(
"""
configure terminal
router bgp 65001 vrf vrf1
no bgp graceful-shutdown
"""
)
# R1 and R3 should see no change to their routes
_, result = _run_cmd_and_check(r1, 'show ip bgp 13.1.1.1/32 json', 'r1/bgp_route_1.json')
assertmsg = 'R1: Route 13.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
_, result = _run_cmd_and_check(r3, 'show ip bgp 11.1.1.1/32 json', 'r3/bgp_route_1.json')
assertmsg = 'R3: Route 11.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
# R5 should see routes from R2 with original attributes.
_, result = _run_cmd_and_check(r5, 'show ip bgp 14.1.1.1/32 json', 'r5/bgp_route_1.json')
assertmsg = 'R5: Route 14.1.1.1/32 not present or has unexpected params'
assert result is None, assertmsg
logger.info('\nTest #5: Successful, routes have their original attributes with default LPREF and without GSHUT')
#tgen.mininet_cli()
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))