]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py
*: auto-convert to SPDX License IDs
[mirror_frr.git] / tests / topotests / ospf_netns_vrf / test_ospf_netns_vrf.py
CommitLineData
35490676 1#!/usr/bin/env python
acddc0ed 2# SPDX-License-Identifier: ISC
35490676
PG
3
4#
f2f5c986 5# test_ospf_netns_vrf.py
35490676
PG
6# Part of NetDEF Topology Tests
7#
8# Copyright (c) 2017 by
9# Network Device Education Foundation, Inc. ("NetDEF")
10#
35490676
PG
11
12"""
f2f5c986 13test_ospf_netns_vrf.py: Test OSPF with Network Namespace VRFs.
35490676
PG
14"""
15
16import os
35490676
PG
17import sys
18from functools import partial
19import pytest
20
21# Save the Current Working Directory to find configuration files.
22CWD = os.path.dirname(os.path.realpath(__file__))
787e7624 23sys.path.append(os.path.join(CWD, "../"))
35490676
PG
24
25# pylint: disable=C0413
26# Import topogen and topotest helpers
27from lib import topotest
28from lib.topogen import Topogen, TopoRouter, get_topogen
29from lib.topolog import logger
30
31# Required to instantiate the topology builder class.
35490676 32
3dedee4f 33pytestmark = [pytest.mark.ospfd]
787e7624 34
5980ad0a 35
e82b531d
CH
36def build_topo(tgen):
37 "Build function"
787e7624 38
e82b531d
CH
39 # Create 3 routers
40 for routern in range(1, 4):
41 tgen.add_router("r{}".format(routern))
35490676 42
e82b531d
CH
43 # Create a empty network for router 1
44 switch = tgen.add_switch("s1")
45 switch.add_link(tgen.gears["r1"])
35490676 46
e82b531d
CH
47 # Create a empty network for router 2
48 switch = tgen.add_switch("s2")
49 switch.add_link(tgen.gears["r2"])
35490676 50
e82b531d
CH
51 # Interconect router 1, 2 and 3
52 switch = tgen.add_switch("s3")
53 switch.add_link(tgen.gears["r1"])
54 switch.add_link(tgen.gears["r2"])
55 switch.add_link(tgen.gears["r3"])
35490676 56
e82b531d
CH
57 # Create empty netowrk for router3
58 switch = tgen.add_switch("s4")
59 switch.add_link(tgen.gears["r3"])
35490676
PG
60
61
62def setup_module(mod):
63 "Sets up the pytest environment"
e82b531d 64 tgen = Topogen(build_topo, mod.__name__)
35490676
PG
65 tgen.start_topology()
66
67 router_list = tgen.routers()
68
69 # check for zebra capability
e5f0ed14 70 for rname, router in router_list.items():
787e7624 71 if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False:
72 return pytest.skip(
73 "Skipping OSPF VRF NETNS feature. VRF NETNS backend not available on FRR"
74 )
75
76 if os.system("ip netns list") != 0:
77 return pytest.skip(
78 "Skipping OSPF VRF NETNS Test. NETNS not available on System"
79 )
35490676 80
787e7624 81 logger.info("Testing with VRF Namespace support")
35490676 82
e5f0ed14 83 for rname, router in router_list.items():
8db751b8
CH
84 # create VRF rx-ospf-cust1 and link rx-eth{0,1} to rx-ospf-cust1
85 ns = "{}-ospf-cust1".format(rname)
86 router.net.add_netns(ns)
87 router.net.set_intf_netns(rname + "-eth0", ns, up=True)
88 router.net.set_intf_netns(rname + "-eth1", ns, up=True)
35490676
PG
89
90 router.load_config(
91 TopoRouter.RD_ZEBRA,
787e7624 92 os.path.join(CWD, "{}/zebra.conf".format(rname)),
93 "--vrfwnetns",
35490676
PG
94 )
95 router.load_config(
787e7624 96 TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
35490676
PG
97 )
98
99 # Initialize all routers.
100 tgen.start_router()
9aecc71d 101 for router in router_list.values():
787e7624 102 if router.has_version("<", "4.0"):
103 tgen.set_error("unsupported version")
9aecc71d 104
35490676
PG
105
106def teardown_module(mod):
107 "Teardown the pytest environment"
108 tgen = get_topogen()
109
8db751b8 110 # Move interfaces out of vrf namespace and delete the namespace
35490676 111 router_list = tgen.routers()
e5f0ed14 112 for rname, router in router_list.items():
8db751b8
CH
113 tgen.net[rname].reset_intf_netns(rname + "-eth0")
114 tgen.net[rname].reset_intf_netns(rname + "-eth1")
115 tgen.net[rname].delete_netns(rname + "-ospf-cust1")
35490676
PG
116 tgen.stop_topology()
117
787e7624 118
35490676 119# Shared test function to validate expected output.
91813876
PG
120def compare_show_ip_route_vrf(rname, expected):
121 """
6a95bfc8 122 Calls 'show ip ospf vrf [rname]-ospf-cust1 route' for router `rname` and compare the obtained
91813876
PG
123 result with the expected output.
124 """
125 tgen = get_topogen()
6a95bfc8 126 vrf_name = "{0}-ospf-cust1".format(rname)
91813876 127 current = topotest.ip4_route_zebra(tgen.gears[rname], vrf_name)
787e7624 128 ret = topotest.difflines(
129 current, expected, title1="Current output", title2="Expected output"
130 )
91813876
PG
131 return ret
132
787e7624 133
35490676
PG
134def test_ospf_convergence():
135 "Test OSPF daemon convergence"
136 tgen = get_topogen()
137
35490676 138 if tgen.routers_have_failure():
787e7624 139 pytest.skip("skipped because of router(s) failure")
35490676 140
e5f0ed14 141 for rname, router in tgen.routers().items():
9aecc71d 142 logger.info('Waiting for router "%s" convergence', rname)
35490676
PG
143
144 # Load expected results from the command
787e7624 145 reffile = os.path.join(CWD, "{}/ospfroute.txt".format(rname))
35490676
PG
146 expected = open(reffile).read()
147
148 # Run test function until we get an result. Wait at most 60 seconds.
787e7624 149 test_func = partial(
150 topotest.router_output_cmp,
151 router,
6a95bfc8 152 "show ip ospf vrf {0}-ospf-cust1 route".format(rname),
787e7624 153 expected,
154 )
155 result, diff = topotest.run_and_expect(test_func, "", count=160, wait=0.5)
156 assertmsg = "OSPF did not converge on {}:\n{}".format(rname, diff)
9aecc71d
RZ
157 assert result, assertmsg
158
35490676
PG
159
160def test_ospf_kernel_route():
161 "Test OSPF kernel route installation"
162 tgen = get_topogen()
9aecc71d 163
35490676 164 if tgen.routers_have_failure():
787e7624 165 pytest.skip("skipped because of router(s) failure")
35490676
PG
166
167 rlist = tgen.routers().values()
168 for router in rlist:
169 logger.info('Checking OSPF IPv4 kernel routes in "%s"', router.name)
787e7624 170 reffile = os.path.join(CWD, "{}/zebraroute.txt".format(router.name))
91813876
PG
171 expected = open(reffile).read()
172 # Run test function until we get an result. Wait at most 60 seconds.
173 test_func = partial(compare_show_ip_route_vrf, router.name, expected)
787e7624 174 result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5)
9aecc71d 175 assertmsg = 'OSPF IPv4 route mismatch in router "{}": {}'.format(
787e7624 176 router.name, diff
177 )
9aecc71d
RZ
178 assert result, assertmsg
179
35490676
PG
180
181def test_ospf_json():
182 "Test 'show ip ospf json' output for coherency."
183 tgen = get_topogen()
9aecc71d 184
35490676 185 if tgen.routers_have_failure():
787e7624 186 pytest.skip("skipped because of router(s) failure")
9aecc71d 187
e5f0ed14 188 for rname, router in tgen.routers().items():
787e7624 189 logger.info(
6a95bfc8 190 'Comparing router "%s" "show ip ospf vrf %s-ospf-cust1 json" output',
787e7624 191 router.name,
192 router.name,
193 )
35490676 194 expected = {
6a95bfc8
CH
195 "{}-ospf-cust1".format(router.name): {
196 "vrfName": "{}-ospf-cust1".format(router.name),
787e7624 197 "routerId": "10.0.255.{}".format(rname[1:]),
198 "tosRoutesOnly": True,
199 "rfc2328Conform": True,
200 "spfScheduleDelayMsecs": 0,
201 "holdtimeMinMsecs": 50,
202 "holdtimeMaxMsecs": 5000,
203 "lsaMinIntervalMsecs": 5000,
204 "lsaMinArrivalMsecs": 1000,
205 "writeMultiplier": 20,
206 "refreshTimerMsecs": 10000,
207 "asbrRouter": "injectingExternalRoutingInformation",
208 "attachedAreaCounter": 1,
209 "areas": {},
35490676 210 }
787e7624 211 }
35490676 212 # Area specific additional checks
787e7624 213 if router.name == "r1" or router.name == "r2" or router.name == "r3":
6a95bfc8 214 expected["{}-ospf-cust1".format(router.name)]["areas"]["0.0.0.0"] = {
787e7624 215 "areaIfActiveCounter": 2,
216 "areaIfTotalCounter": 2,
217 "authentication": "authenticationNone",
218 "backbone": True,
219 "lsaAsbrNumber": 0,
220 "lsaNetworkNumber": 1,
221 "lsaNssaNumber": 0,
222 "lsaNumber": 4,
223 "lsaOpaqueAreaNumber": 0,
224 "lsaOpaqueLinkNumber": 0,
225 "lsaRouterNumber": 3,
226 "lsaSummaryNumber": 0,
227 "nbrFullAdjacentCounter": 2,
35490676
PG
228 }
229
787e7624 230 test_func = partial(
231 topotest.router_json_cmp,
232 router,
6a95bfc8 233 "show ip ospf vrf {0}-ospf-cust1 json".format(rname),
787e7624 234 expected,
235 )
236 _, diff = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
9aecc71d
RZ
237 assertmsg = '"{}" JSON output mismatches'.format(rname)
238 assert diff is None, assertmsg
239
35490676
PG
240
241def test_ospf_link_down():
242 "Test OSPF convergence after a link goes down"
243 tgen = get_topogen()
9aecc71d 244
35490676 245 if tgen.routers_have_failure():
787e7624 246 pytest.skip("skipped because of router(s) failure")
35490676
PG
247
248 # Simulate a network down event on router3 switch3 interface.
787e7624 249 router3 = tgen.gears["r3"]
250 topotest.interface_set_status(
6a95bfc8 251 router3, "r3-eth0", ifaceaction=False, vrf_name="r3-ospf-cust1"
787e7624 252 )
35490676
PG
253
254 # Expect convergence on all routers
e5f0ed14 255 for rname, router in tgen.routers().items():
9aecc71d 256 logger.info('Waiting for router "%s" convergence after link failure', rname)
35490676 257 # Load expected results from the command
787e7624 258 reffile = os.path.join(CWD, "{}/ospfroute_down.txt".format(rname))
35490676
PG
259 expected = open(reffile).read()
260
261 # Run test function until we get an result. Wait at most 60 seconds.
787e7624 262 test_func = partial(
263 topotest.router_output_cmp,
264 router,
6a95bfc8 265 "show ip ospf vrf {0}-ospf-cust1 route".format(rname),
787e7624 266 expected,
267 )
268 result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5)
269 assertmsg = "OSPF did not converge on {}:\n{}".format(rname, diff)
9aecc71d
RZ
270 assert result, assertmsg
271
35490676
PG
272
273def test_ospf_link_down_kernel_route():
274 "Test OSPF kernel route installation"
275 tgen = get_topogen()
9aecc71d 276
35490676 277 if tgen.routers_have_failure():
787e7624 278 pytest.skip("skipped because of router(s) failure")
35490676
PG
279
280 rlist = tgen.routers().values()
281 for router in rlist:
787e7624 282 logger.info(
283 'Checking OSPF IPv4 kernel routes in "%s" after link down', router.name
284 )
35490676 285
6a95bfc8 286 str = "{0}-ospf-cust1".format(router.name)
787e7624 287 reffile = os.path.join(CWD, "{}/zebraroutedown.txt".format(router.name))
91813876
PG
288 expected = open(reffile).read()
289 # Run test function until we get an result. Wait at most 60 seconds.
290 test_func = partial(compare_show_ip_route_vrf, router.name, expected)
787e7624 291 result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5)
9fa6ec14 292 assertmsg = (
293 'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format(
294 router.name, diff
295 )
787e7624 296 )
9aecc71d
RZ
297 assert result, assertmsg
298
35490676
PG
299
300def test_memory_leak():
301 "Run the memory leak test and report results."
302 tgen = get_topogen()
303 if not tgen.is_memleak_enabled():
787e7624 304 pytest.skip("Memory leak test/report is disabled")
35490676
PG
305
306 tgen.report_memory_leaks()
307
787e7624 308
309if __name__ == "__main__":
35490676
PG
310 args = ["-s"] + sys.argv[1:]
311 sys.exit(pytest.main(args))