]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/bfd_isis_topo1/test_bfd_isis_topo1.py
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / tests / topotests / bfd_isis_topo1 / test_bfd_isis_topo1.py
1 #!/usr/bin/env python
2
3 #
4 # test_bfd_isis_topo1.py
5 # Part of NetDEF Topology Tests
6 #
7 # Copyright (c) 2020 by
8 # Network Device Education Foundation, Inc. ("NetDEF")
9 #
10 # Permission to use, copy, modify, and/or distribute this software
11 # for any purpose with or without fee is hereby granted, provided
12 # that the above copyright notice and this permission notice appear
13 # in all copies.
14 #
15 # THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
16 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
17 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
18 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
19 # DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 # WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
21 # ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 # OF THIS SOFTWARE.
23 #
24
25 """
26 test_bfd_isis_topo1.py:
27
28 +---------+
29 | |
30 eth-rt2 (.1) | RT1 | eth-rt3 (.1)
31 +----------+ 1.1.1.1 +----------+
32 | | | |
33 | +---------+ |
34 | |
35 | 10.0.2.0/24 |
36 | |
37 | eth-rt1 | (.2)
38 | 10.0.1.0/24 +----+----+
39 | | |
40 | | RT3 |
41 | | 3.3.3.3 |
42 | | |
43 (.2) | eth-rt1 +----+----+
44 +----+----+ eth-rt4 | (.1)
45 | | |
46 | RT2 | |
47 | 2.2.2.2 | 10.0.4.0/24 |
48 | | |
49 +----+----+ |
50 (.1) | eth-rt5 eth-rt3 | (.2)
51 | +----+----+
52 | | |
53 | | RT4 |
54 | | 4.4.4.4 |
55 | | |
56 | +----+----+
57 | 10.0.3.0/24 eth-rt5 | (.1)
58 | |
59 | |
60 | 10.0.5.0/24 |
61 | |
62 | +---------+ |
63 | | | |
64 +----------+ RT5 +----------+
65 eth-rt2 (.2) | 5.5.5.5 | eth-rt4 (.2)
66 | |
67 +---------+
68
69 """
70
71 import os
72 import sys
73 import pytest
74 import json
75 from functools import partial
76
77 # Save the Current Working Directory to find configuration files.
78 CWD = os.path.dirname(os.path.realpath(__file__))
79 sys.path.append(os.path.join(CWD, "../"))
80
81 # pylint: disable=C0413
82 # Import topogen and topotest helpers
83 from lib import topotest
84 from lib.topogen import Topogen, TopoRouter, get_topogen
85 from lib.topolog import logger
86
87 pytestmark = [pytest.mark.bfdd, pytest.mark.isisd]
88
89
90 def setup_module(mod):
91 "Sets up the pytest environment"
92 topodef = {
93 "s1": ("rt1:eth-rt2", "rt2:eth-rt1"),
94 "s2": ("rt1:eth-rt3", "rt3:eth-rt1"),
95 "s3": ("rt2:eth-rt5", "rt5:eth-rt2"),
96 "s4": ("rt3:eth-rt4", "rt4:eth-rt3"),
97 "s5": ("rt4:eth-rt5", "rt5:eth-rt4"),
98 }
99 tgen = Topogen(topodef, mod.__name__)
100 tgen.start_topology()
101
102 router_list = tgen.routers()
103
104 # For all registered routers, load the zebra configuration file
105 for rname, router in router_list.items():
106 router.load_config(
107 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
108 )
109 router.load_config(
110 TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
111 )
112 router.load_config(
113 TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
114 )
115
116 tgen.start_router()
117
118
119 def teardown_module(mod):
120 "Teardown the pytest environment"
121 tgen = get_topogen()
122
123 # This function tears down the whole topology.
124 tgen.stop_topology()
125
126
127 def print_cmd_result(rname, command):
128 print(get_topogen().gears[rname].vtysh_cmd(command, isjson=False))
129
130
131 def router_compare_json_output(rname, command, reference, count=120, wait=0.5):
132 "Compare router JSON output"
133
134 logger.info('Comparing router "%s" "%s" output', rname, command)
135
136 tgen = get_topogen()
137 filename = "{}/{}/{}".format(CWD, rname, reference)
138 expected = json.loads(open(filename).read())
139
140 # Run test function until we get an result. Wait at most 60 seconds.
141 test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
142 _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait)
143 assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
144 assert diff is None, assertmsg
145
146
147 ## TEST STEPS
148
149
150 def test_rib_isis_step1():
151 logger.info("Test (step 1): verify RIB (IPv4 and IPv6) for IS-IS")
152 tgen = get_topogen()
153
154 # Skip if previous fatal error condition is raised
155 if tgen.routers_have_failure():
156 pytest.skip(tgen.errors)
157
158 router_compare_json_output(
159 "rt1", "show ip route isis json", "step1/show_ip_route.ref"
160 )
161 router_compare_json_output(
162 "rt1", "show ipv6 route isis json", "step1/show_ipv6_route.ref"
163 )
164
165
166 def test_bfd_isis_sessions_step2():
167 logger.info("Test (step 2): verify BFD peers for IS-IS")
168 tgen = get_topogen()
169
170 # Skip if previous fatal error condition is raised
171 if tgen.routers_have_failure():
172 pytest.skip(tgen.errors)
173
174 # BFD is just used on three routers
175 for rt in ["rt1", "rt2", "rt3"]:
176 router_compare_json_output(
177 rt, "show bfd peers json", "step2/show_bfd_peers.ref"
178 )
179
180
181 def test_bfd_isis_interface_failure_rt2_step3():
182 logger.info("Test (step 2): check failover handling when RT2 goes down")
183 tgen = get_topogen()
184
185 # Skip if previous fatal error condition is raised
186 if tgen.routers_have_failure():
187 pytest.skip(tgen.errors)
188
189 # Let's kill the interface on rt2 and see what happens with the RIB and BFD on rt1
190 tgen.gears["rt2"].link_enable("eth-rt1", enabled=False)
191
192 # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
193 # initial 2 seconds to let the CI not suffer.
194 # TODO: add check for array size
195 router_compare_json_output(
196 "rt1", "show ip route isis json", "step3/show_ip_route_rt2_down.ref", 20, 1
197 )
198 router_compare_json_output(
199 "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_rt2_down.ref", 20, 1
200 )
201 router_compare_json_output(
202 "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 20, 1
203 )
204
205 # Check recovery, this can take some time
206 tgen.gears["rt2"].link_enable("eth-rt1", enabled=True)
207
208 router_compare_json_output(
209 "rt1", "show ip route isis json", "step3/show_ip_route_healthy.ref"
210 )
211 router_compare_json_output(
212 "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_healthy.ref"
213 )
214 router_compare_json_output(
215 "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref"
216 )
217
218
219 def test_bfd_isis_interface_failure_rt3_step3():
220 logger.info("Test (step 2): check failover handling when RT2 goes down")
221 tgen = get_topogen()
222
223 # Skip if previous fatal error condition is raised
224 if tgen.routers_have_failure():
225 pytest.skip(tgen.errors)
226
227 # Let's kill the interface on rt3 and see what happens with the RIB and BFD on rt1
228 tgen.gears["rt3"].link_enable("eth-rt1", enabled=False)
229
230 # By default BFD provides a recovery time of 900ms plus jitter, so let's wait
231 # initial 2 seconds to let the CI not suffer.
232 # TODO: add check for array size
233 router_compare_json_output(
234 "rt1", "show ip route isis json", "step3/show_ip_route_rt3_down.ref", 20, 1
235 )
236 router_compare_json_output(
237 "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_rt3_down.ref", 20, 1
238 )
239 router_compare_json_output(
240 "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 20, 1
241 )
242
243 # Check recovery, this can take some time
244 tgen.gears["rt3"].link_enable("eth-rt1", enabled=True)
245
246 router_compare_json_output(
247 "rt1", "show ip route isis json", "step3/show_ip_route_healthy.ref"
248 )
249 router_compare_json_output(
250 "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_healthy.ref"
251 )
252 router_compare_json_output(
253 "rt1", "show bfd peers json", "step3/show_bfd_peers_healthy.ref"
254 )
255
256
257 def test_memory_leak():
258 "Run the memory leak test and report results."
259 tgen = get_topogen()
260 if not tgen.is_memleak_enabled():
261 pytest.skip("Memory leak test/report is disabled")
262
263 tgen.report_memory_leaks()
264
265
266 if __name__ == "__main__":
267 args = ["-s"] + sys.argv[1:]
268 sys.exit(pytest.main(args))