mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-26 02:13:04 +00:00
tests: Updated topotest and documentation
Added topotest and documentation for BGP wide GR configurations Signed-off-by: Pooja Jagadeesh Doijode <pdoijode@nvidia.com>
This commit is contained in:
parent
c30b683338
commit
ecbca1ae1b
@ -1080,6 +1080,52 @@ 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-config-mode-cmd:
|
||||
|
||||
BGP GR Config Mode Commands
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. clicmd:: bgp graceful-restart
|
||||
|
||||
This command will enable BGP graceful restart functionality for all BGP instances.
|
||||
|
||||
.. clicmd:: bgp graceful-restart-disable
|
||||
|
||||
This command will disable both the functionality graceful restart and helper
|
||||
mode for all BGP instances
|
||||
|
||||
.. clicmd:: bgp graceful-restart select-defer-time (0-3600)
|
||||
|
||||
This is command, will set deferral time to value specified.
|
||||
|
||||
.. clicmd:: bgp graceful-restart rib-stale-time (1-3600)
|
||||
|
||||
This is command, will set the time for which stale routes are kept in RIB.
|
||||
|
||||
.. clicmd:: bgp graceful-restart restart-time (0-4095)
|
||||
|
||||
Set the time to wait to delete stale routes before a BGP open message
|
||||
is received.
|
||||
|
||||
Using with Long-lived Graceful Restart capability, this is recommended
|
||||
setting this timer to 0 and control stale routes with
|
||||
``bgp long-lived-graceful-restart stale-time``.
|
||||
|
||||
Default value is 120.
|
||||
|
||||
.. clicmd:: bgp graceful-restart stalepath-time (1-4095)
|
||||
|
||||
This is command, will set the max time (in seconds) to hold onto
|
||||
restarting peer's stale paths.
|
||||
|
||||
It also controls Enhanced Route-Refresh timer.
|
||||
|
||||
If this command is configured and the router does not receive a Route-Refresh EoRR
|
||||
message, the router removes the stale routes from the BGP table after the timer
|
||||
expires. The stale path timer is started when the router receives a Route-Refresh
|
||||
BoRR message
|
||||
|
||||
|
||||
.. _bgp-GR-global-mode-cmd:
|
||||
|
||||
BGP GR Global Mode Commands
|
||||
|
@ -81,6 +81,8 @@ import os
|
||||
import sys
|
||||
import time
|
||||
import pytest
|
||||
import functools
|
||||
import json
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
@ -91,6 +93,7 @@ sys.path.append(os.path.join("../lib/"))
|
||||
# Import topogen and topotest helpers
|
||||
from lib.topogen import Topogen, get_topogen
|
||||
from lib.topolog import logger
|
||||
from lib import topotest
|
||||
|
||||
# Required to instantiate the topology builder class.
|
||||
|
||||
@ -1680,6 +1683,304 @@ def BGP_GR_TC_52_p1(request):
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
def test_BGP_GR_TC_53_p1(request):
|
||||
"""
|
||||
Test Objective : Peer-level inherit from BGP wide Restarting
|
||||
Global Mode : GR Restart
|
||||
PerPeer Mode : None
|
||||
GR Mode effective : GR Restart
|
||||
|
||||
"""
|
||||
|
||||
tgen = get_topogen()
|
||||
tc_name = request.node.name
|
||||
write_test_header(tc_name)
|
||||
|
||||
# Check router status
|
||||
check_router_status(tgen)
|
||||
|
||||
# Don't run this test if we have any failure.
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
# Creating configuration from JSON
|
||||
reset_config_on_routers(tgen)
|
||||
|
||||
step("Configure R1 as GR restarting node in global level")
|
||||
|
||||
input_dict = {
|
||||
"r1": {"graceful-restart": {"graceful-restart": True}},
|
||||
"r2": {"graceful-restart": {"graceful-restart-helper": True}},
|
||||
}
|
||||
|
||||
output = tgen.gears["r1"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
bgp graceful-restart
|
||||
!
|
||||
"""
|
||||
)
|
||||
|
||||
step("Verify that R2 receives GR restarting capabilities" " from R1")
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
result = verify_graceful_restart(
|
||||
tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
|
||||
)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
result = verify_graceful_restart(
|
||||
tgen, topo, addr_type, input_dict, dut="r2", peer="r1"
|
||||
)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
dut = "r1"
|
||||
peer = "r2"
|
||||
protocol = "bgp"
|
||||
next_hop = next_hop_per_address_family(
|
||||
tgen, dut, peer, addr_type, NEXT_HOP_IP_2
|
||||
)
|
||||
input_topo = {"r2": topo["routers"]["r2"]}
|
||||
result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
dut = "r2"
|
||||
peer = "r1"
|
||||
next_hop = next_hop_per_address_family(
|
||||
tgen, dut, peer, addr_type, NEXT_HOP_IP_1
|
||||
)
|
||||
input_topo = {"r1": topo["routers"]["r1"]}
|
||||
result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
step("Kill BGPd on router R1")
|
||||
|
||||
kill_router_daemons(tgen, "r1", ["bgpd"])
|
||||
|
||||
step(
|
||||
"Verify that R1 keeps the stale entries in FIB and R2 keeps stale entries in RIB & FIB"
|
||||
)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
dut = "r1"
|
||||
peer = "r2"
|
||||
protocol = "bgp"
|
||||
next_hop = next_hop_per_address_family(
|
||||
tgen, dut, peer, addr_type, NEXT_HOP_IP_2
|
||||
)
|
||||
input_topo = {"r2": topo["routers"]["r2"]}
|
||||
result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
dut = "r2"
|
||||
peer = "r1"
|
||||
next_hop = next_hop_per_address_family(
|
||||
tgen, dut, peer, addr_type, NEXT_HOP_IP_1
|
||||
)
|
||||
input_topo = {"r1": topo["routers"]["r1"]}
|
||||
result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
# Configure graceful-restart-disable at config global level verify that the functionality works
|
||||
step("Bring up BGP on R1 and configure graceful-restart-disable")
|
||||
|
||||
start_router_daemons(tgen, "r1", ["bgpd"])
|
||||
|
||||
input_dict = {
|
||||
"r1": {"graceful-restart": {"graceful-restart-disable": True}},
|
||||
"r2": {"graceful-restart": {"graceful-restart-helper": True}},
|
||||
}
|
||||
|
||||
output = tgen.gears["r1"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
bgp graceful-restart-disable
|
||||
!
|
||||
"""
|
||||
)
|
||||
|
||||
step("Verify on R2 that R1 does't advertise any GR capabilities")
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
result = verify_graceful_restart(
|
||||
tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
|
||||
)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
result = verify_graceful_restart(
|
||||
tgen, topo, addr_type, input_dict, dut="r2", peer="r1"
|
||||
)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
dut = "r1"
|
||||
peer = "r2"
|
||||
protocol = "bgp"
|
||||
next_hop = next_hop_per_address_family(
|
||||
tgen, dut, peer, addr_type, NEXT_HOP_IP_2
|
||||
)
|
||||
input_topo = {"r2": topo["routers"]["r2"]}
|
||||
result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
dut = "r2"
|
||||
peer = "r1"
|
||||
next_hop = next_hop_per_address_family(
|
||||
tgen, dut, peer, addr_type, NEXT_HOP_IP_1
|
||||
)
|
||||
input_topo = {"r1": topo["routers"]["r1"]}
|
||||
result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
|
||||
assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
|
||||
|
||||
step("Kill BGP on R1")
|
||||
|
||||
kill_router_daemons(tgen, "r1", ["bgpd"])
|
||||
|
||||
step("Verify on R2 and R1 that none of the routers keep stale entries")
|
||||
|
||||
for addr_type in ADDR_TYPES:
|
||||
dut = "r1"
|
||||
peer = "r2"
|
||||
protocol = "bgp"
|
||||
next_hop = next_hop_per_address_family(
|
||||
tgen, dut, peer, addr_type, NEXT_HOP_IP_2
|
||||
)
|
||||
input_topo = {"r2": topo["routers"]["r2"]}
|
||||
result = verify_rib(
|
||||
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
|
||||
)
|
||||
assert result is not True, (
|
||||
"Testcase {} : Failed \n "
|
||||
"Expected: Routes should not be present in {} FIB \n "
|
||||
"Found: {}".format(tc_name, dut, result)
|
||||
)
|
||||
|
||||
dut = "r2"
|
||||
peer = "r1"
|
||||
next_hop = next_hop_per_address_family(
|
||||
tgen, dut, peer, addr_type, NEXT_HOP_IP_1
|
||||
)
|
||||
input_topo = {"r1": topo["routers"]["r1"]}
|
||||
result = verify_bgp_rib(
|
||||
tgen, addr_type, dut, input_topo, next_hop, expected=False
|
||||
)
|
||||
assert result is not True, (
|
||||
"Testcase {} : Failed \n "
|
||||
"Expected: Routes should not be present in {} BGP RIB \n "
|
||||
"Found: {}".format(tc_name, dut, result)
|
||||
)
|
||||
|
||||
result = verify_rib(
|
||||
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
|
||||
)
|
||||
assert result is not True, (
|
||||
"Testcase {} : Failed \n "
|
||||
"Expected: Routes should not be present in {} FIB \n "
|
||||
"Found: {}".format(tc_name, dut, result)
|
||||
)
|
||||
|
||||
step(
|
||||
"Bring up BGP on R1, enable GR and configure bgp graceful-restart restart-time at global level"
|
||||
)
|
||||
|
||||
start_router_daemons(tgen, "r1", ["bgpd"])
|
||||
|
||||
output = tgen.gears["r1"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
no bgp graceful-restart-disable
|
||||
bgp graceful-restart
|
||||
bgp graceful-restart stalepath-time 420
|
||||
bgp graceful-restart restart-time 240
|
||||
bgp graceful-restart select-defer-time 420
|
||||
!
|
||||
"""
|
||||
)
|
||||
|
||||
step("Verify on R2 that R1 sent the updated GR restart-time")
|
||||
|
||||
def _bgp_check_if_gr_restart_time_was_updated():
|
||||
output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp neighbor json"))
|
||||
|
||||
expected = {
|
||||
"192.168.0.1": {
|
||||
"gracefulRestartInfo": {
|
||||
"localGrMode": "Helper*",
|
||||
"remoteGrMode": "Restart",
|
||||
"timers": {
|
||||
"configuredRestartTimer": 120,
|
||||
"receivedRestartTimer": 240,
|
||||
},
|
||||
},
|
||||
},
|
||||
"fd00::1": {
|
||||
"gracefulRestartInfo": {
|
||||
"localGrMode": "Helper*",
|
||||
"remoteGrMode": "Restart",
|
||||
"timers": {
|
||||
"configuredRestartTimer": 120,
|
||||
"receivedRestartTimer": 240,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return topotest.json_cmp(output, expected)
|
||||
|
||||
test_func = functools.partial(
|
||||
_bgp_check_if_gr_restart_time_was_updated,
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||
assert result is None, "R2 did not receive the updated GR restart-time of 240s"
|
||||
|
||||
def _bgp_check_if_gr_timer_on_restarting_node_was_updated():
|
||||
output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp neighbor json"))
|
||||
|
||||
expected = {
|
||||
"192.168.0.2": {
|
||||
"gracefulRestartInfo": {
|
||||
"localGrMode": "Restart*",
|
||||
"remoteGrMode": "Helper",
|
||||
"timers": {
|
||||
"configuredRestartTimer": 240,
|
||||
"receivedRestartTimer": 120,
|
||||
},
|
||||
"ipv4Unicast": {
|
||||
"timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420}
|
||||
},
|
||||
},
|
||||
},
|
||||
"fd00::2": {
|
||||
"gracefulRestartInfo": {
|
||||
"localGrMode": "Restart*",
|
||||
"remoteGrMode": "Helper",
|
||||
"timers": {
|
||||
"configuredRestartTimer": 240,
|
||||
"receivedRestartTimer": 120,
|
||||
},
|
||||
"ipv6Unicast": {
|
||||
"timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
return topotest.json_cmp(output, expected)
|
||||
|
||||
test_func = functools.partial(
|
||||
_bgp_check_if_gr_timer_on_restarting_node_was_updated,
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||
assert (
|
||||
result is None
|
||||
), "R1 did not update the GR select-deferral and stale-path timer to 420s"
|
||||
|
||||
write_test_footer(tc_name)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
||||
|
@ -195,16 +195,16 @@ def test_bgp_administrative_reset_gr():
|
||||
step("Reset and shutdown R1")
|
||||
_bgp_clear_r1_and_shutdown()
|
||||
|
||||
step("Check if Hard Reset notification wasn't sent from R2")
|
||||
test_func = functools.partial(_bgp_check_hard_reset)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assert result is None, "Failed to send Administrative Reset notification from R2"
|
||||
|
||||
step("Check if stale routes are retained on R1")
|
||||
test_func = functools.partial(_bgp_check_gr_notification_stale)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assert result is None, "Failed to see retained stale routes on R1"
|
||||
|
||||
step("Check if Hard Reset notification wasn't sent from R2")
|
||||
test_func = functools.partial(_bgp_check_hard_reset)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assert result is None, "Failed to send Administrative Reset notification from R2"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
|
@ -3266,27 +3266,48 @@ def verify_graceful_restart(
|
||||
|
||||
lmode = None
|
||||
rmode = None
|
||||
|
||||
# Local GR mode
|
||||
if "address_family" in input_dict[dut]["bgp"]:
|
||||
bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][
|
||||
if "bgp" not in input_dict[dut] and "graceful-restart" in input_dict[dut]:
|
||||
if (
|
||||
"graceful-restart" in input_dict[dut]["graceful-restart"]
|
||||
and input_dict[dut]["graceful-restart"][
|
||||
"graceful-restart"
|
||||
]
|
||||
):
|
||||
lmode = "Restart*"
|
||||
elif (
|
||||
"graceful-restart-disable"
|
||||
in input_dict[dut]["graceful-restart"]
|
||||
and input_dict[dut]["graceful-restart"][
|
||||
"graceful-restart-disable"
|
||||
]
|
||||
):
|
||||
lmode = "Disable*"
|
||||
else:
|
||||
lmode = "Helper*"
|
||||
|
||||
if lmode is None:
|
||||
if "address_family" in input_dict[dut]["bgp"]:
|
||||
bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][
|
||||
"unicast"
|
||||
]["neighbor"][peer]["dest_link"]
|
||||
|
||||
for dest_link, data in bgp_neighbors.items():
|
||||
if (
|
||||
"graceful-restart-helper" in data
|
||||
and data["graceful-restart-helper"]
|
||||
):
|
||||
lmode = "Helper"
|
||||
elif "graceful-restart" in data and data["graceful-restart"]:
|
||||
lmode = "Restart"
|
||||
elif (
|
||||
"graceful-restart-disable" in data
|
||||
and data["graceful-restart-disable"]
|
||||
):
|
||||
lmode = "Disable"
|
||||
else:
|
||||
lmode = None
|
||||
for dest_link, data in bgp_neighbors.items():
|
||||
if (
|
||||
"graceful-restart-helper" in data
|
||||
and data["graceful-restart-helper"]
|
||||
):
|
||||
lmode = "Helper"
|
||||
elif "graceful-restart" in data and data["graceful-restart"]:
|
||||
lmode = "Restart"
|
||||
elif (
|
||||
"graceful-restart-disable" in data
|
||||
and data["graceful-restart-disable"]
|
||||
):
|
||||
lmode = "Disable"
|
||||
else:
|
||||
lmode = None
|
||||
|
||||
if lmode is None:
|
||||
if "graceful-restart" in input_dict[dut]["bgp"]:
|
||||
@ -3314,7 +3335,8 @@ def verify_graceful_restart(
|
||||
return True
|
||||
|
||||
# Remote GR mode
|
||||
if "address_family" in input_dict[peer]["bgp"]:
|
||||
|
||||
if "bgp" in input_dict[peer] and "address_family" in input_dict[peer]["bgp"]:
|
||||
bgp_neighbors = input_dict[peer]["bgp"]["address_family"][addr_type][
|
||||
"unicast"
|
||||
]["neighbor"][dut]["dest_link"]
|
||||
@ -3336,7 +3358,7 @@ def verify_graceful_restart(
|
||||
rmode = None
|
||||
|
||||
if rmode is None:
|
||||
if "graceful-restart" in input_dict[peer]["bgp"]:
|
||||
if "bgp" in input_dict[peer] and "graceful-restart" in input_dict[peer]["bgp"]:
|
||||
if (
|
||||
"graceful-restart"
|
||||
in input_dict[peer]["bgp"]["graceful-restart"]
|
||||
@ -3355,6 +3377,27 @@ def verify_graceful_restart(
|
||||
rmode = "Disable"
|
||||
else:
|
||||
rmode = "Helper"
|
||||
|
||||
if rmode is None:
|
||||
if "bgp" not in input_dict[peer] and "graceful-restart" in input_dict[peer]:
|
||||
if (
|
||||
"graceful-restart"
|
||||
in input_dict[peer]["graceful-restart"]
|
||||
and input_dict[peer]["graceful-restart"][
|
||||
"graceful-restart"
|
||||
]
|
||||
):
|
||||
rmode = "Restart"
|
||||
elif (
|
||||
"graceful-restart-disable"
|
||||
in input_dict[peer]["graceful-restart"]
|
||||
and input_dict[peer]["graceful-restart"][
|
||||
"graceful-restart-disable"
|
||||
]
|
||||
):
|
||||
rmode = "Disable"
|
||||
else:
|
||||
rmode = "Helper"
|
||||
else:
|
||||
rmode = "Helper"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user