242 lines
6.1 KiB
Python
242 lines
6.1 KiB
Python
#!/usr/bin/env python
|
|
# SPDX-License-Identifier: ISC
|
|
|
|
#
|
|
# test_rip_bfd_topo1.py
|
|
# Part of NetDEF Topology Tests
|
|
#
|
|
# Copyright (c) 2023 by
|
|
# Network Device Education Foundation, Inc. ("NetDEF")
|
|
#
|
|
|
|
"""
|
|
test_rip_bfd_topo1.py: Test RIP BFD integration.
|
|
"""
|
|
|
|
import sys
|
|
import re
|
|
import pytest
|
|
|
|
from functools import partial
|
|
from lib import topotest
|
|
from lib.topogen import Topogen, TopoRouter
|
|
from lib.topolog import logger
|
|
|
|
pytestmark = [
|
|
pytest.mark.bfdd,
|
|
pytest.mark.ripd,
|
|
]
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def tgen(request):
|
|
"Setup/Teardown the environment and provide tgen argument to tests"
|
|
|
|
topodef = {"s1": ("r1", "r2"), "s2": ("r1", "r3")}
|
|
tgen = Topogen(topodef, request.module.__name__)
|
|
tgen.start_topology()
|
|
|
|
router_list = tgen.routers()
|
|
|
|
for router_name, router in router_list.items():
|
|
router.load_config(TopoRouter.RD_BFD, "bfdd.conf")
|
|
router.load_config(TopoRouter.RD_RIP, "ripd.conf")
|
|
router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf")
|
|
if router_name in ["r2", "r3"]:
|
|
router.load_config(TopoRouter.RD_STATIC, "staticd.conf")
|
|
|
|
tgen.start_router()
|
|
yield tgen
|
|
tgen.stop_topology()
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def skip_on_failure(tgen):
|
|
"Test if routers is still running otherwise skip tests"
|
|
if tgen.routers_have_failure():
|
|
pytest.skip("skipped because of previous test failure")
|
|
|
|
|
|
def show_rip_json(router):
|
|
"Get router 'show ip rip' JSON output"
|
|
output = router.vtysh_cmd("show ip rip")
|
|
routes = output.splitlines()[6:]
|
|
json = {}
|
|
|
|
for route in routes:
|
|
match = re.match(
|
|
r"(.)\((.)\)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)", route
|
|
)
|
|
if match is None:
|
|
continue
|
|
|
|
route_entry = {
|
|
"code": match[1],
|
|
"subCode": match[2],
|
|
"nextHop": match[4],
|
|
"metric": int(match[5]),
|
|
"from": match[6],
|
|
}
|
|
|
|
if json.get(match[3]) is None:
|
|
json[match[3]] = []
|
|
|
|
json[match[3]].append(route_entry)
|
|
|
|
return json
|
|
|
|
|
|
def expect_routes(router, routes, time_amount):
|
|
"Expect 'routes' in 'router'."
|
|
|
|
def test_function():
|
|
"Internal test function."
|
|
return topotest.json_cmp(show_rip_json(router), routes)
|
|
|
|
_, result = topotest.run_and_expect(test_function, None, count=time_amount, wait=1)
|
|
assert result is None, "Unexpected routing table in {}".format(router.name)
|
|
|
|
|
|
def expect_bfd_peers(router, peers):
|
|
"Expect 'peers' in 'router' BFD status."
|
|
test_func = partial(
|
|
topotest.router_json_cmp,
|
|
router,
|
|
"show bfd peers json",
|
|
peers,
|
|
)
|
|
_, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
|
|
assert result is None, "{} BFD peer status mismatch".format(router)
|
|
|
|
|
|
def test_rip_convergence(tgen):
|
|
"Test that RIP learns the neighbor routes."
|
|
|
|
expect_routes(
|
|
tgen.gears["r1"],
|
|
{
|
|
"10.254.254.2/32": [{"code": "R", "subCode": "n", "from": "192.168.0.2"}],
|
|
"10.254.254.3/32": [{"code": "R", "subCode": "n", "from": "192.168.1.2"}],
|
|
"10.254.254.100/32": [
|
|
{
|
|
"code": "R",
|
|
"subCode": "n",
|
|
"from": "192.168.0.2",
|
|
},
|
|
{
|
|
"code": "R",
|
|
"subCode": "n",
|
|
"from": "192.168.1.2",
|
|
},
|
|
],
|
|
},
|
|
40,
|
|
)
|
|
|
|
expect_bfd_peers(
|
|
tgen.gears["r1"],
|
|
[
|
|
{
|
|
"peer": "192.168.0.2",
|
|
"status": "up",
|
|
"receive-interval": 1000,
|
|
"transmit-interval": 1000,
|
|
},
|
|
{
|
|
"peer": "192.168.1.2",
|
|
"status": "up",
|
|
"receive-interval": 1000,
|
|
"transmit-interval": 1000,
|
|
},
|
|
],
|
|
)
|
|
|
|
expect_routes(
|
|
tgen.gears["r2"],
|
|
{
|
|
"10.254.254.1/32": [{"code": "R", "subCode": "n", "from": "192.168.0.1"}],
|
|
"10.254.254.3/32": [{"code": "R", "subCode": "n", "from": "192.168.0.1"}],
|
|
"10.254.254.100/32": [{"code": "S", "subCode": "r", "from": "self"}],
|
|
},
|
|
40,
|
|
)
|
|
|
|
expect_bfd_peers(
|
|
tgen.gears["r2"],
|
|
[
|
|
{
|
|
"peer": "192.168.0.1",
|
|
"status": "up",
|
|
"receive-interval": 1000,
|
|
"transmit-interval": 1000,
|
|
}
|
|
],
|
|
)
|
|
|
|
expect_routes(
|
|
tgen.gears["r3"],
|
|
{
|
|
"10.254.254.1/32": [{"code": "R", "subCode": "n", "from": "192.168.1.1"}],
|
|
"10.254.254.2/32": [{"code": "R", "subCode": "n", "from": "192.168.1.1"}],
|
|
"10.254.254.100/32": [{"code": "S", "subCode": "r", "from": "self"}],
|
|
},
|
|
40,
|
|
)
|
|
|
|
expect_bfd_peers(
|
|
tgen.gears["r3"],
|
|
[
|
|
{
|
|
"peer": "192.168.1.1",
|
|
"status": "up",
|
|
"receive-interval": 1000,
|
|
"transmit-interval": 1000,
|
|
}
|
|
],
|
|
)
|
|
|
|
|
|
def test_rip_bfd_convergence(tgen):
|
|
"Test that RIP drop the gone neighbor routes."
|
|
|
|
tgen.gears["r3"].link_enable("r3-eth0", False)
|
|
|
|
expect_routes(
|
|
tgen.gears["r1"],
|
|
{
|
|
"10.254.254.2/32": [{"code": "R", "subCode": "n", "from": "192.168.0.2"}],
|
|
"10.254.254.3/32": None,
|
|
"10.254.254.100/32": [
|
|
{
|
|
"code": "R",
|
|
"subCode": "n",
|
|
"from": "192.168.0.2",
|
|
}
|
|
],
|
|
},
|
|
6,
|
|
)
|
|
|
|
expect_routes(
|
|
tgen.gears["r3"],
|
|
{
|
|
"10.254.254.1/32": None,
|
|
"10.254.254.2/32": None,
|
|
"10.254.254.100/32": [{"code": "S", "subCode": "r", "from": "self"}],
|
|
},
|
|
6,
|
|
)
|
|
|
|
|
|
def test_memory_leak(tgen):
|
|
"Run the memory leak test and report results."
|
|
|
|
if not tgen.is_memleak_enabled():
|
|
pytest.skip("Memory leak test/report is disabled")
|
|
|
|
tgen.report_memory_leaks()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
args = ["-s"] + sys.argv[1:]
|
|
sys.exit(pytest.main(args))
|