]> git.proxmox.com Git - mirror_frr.git/blob - tests/topotests/pim_acl/test_pim_acl.py
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[mirror_frr.git] / tests / topotests / pim_acl / test_pim_acl.py
1 #!/usr/bin/env python
2
3 #
4 # test_pim_acl.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_pim_acl.py: Test PIM with RP selection using ACLs
27 """
28
29 # Test PIM RP selection with ACLs
30 #
31 # Testing RP selection with ACLs. R1 uses multiple ACLs
32 # to select desired RPs (R11 to R15)
33 #
34 # Test steps:
35 # - setup_module()
36 # Create topology. Hosts are only using zebra/staticd,
37 # no PIM, no OSPF (using IGMPv2 for multicast)
38 # - test_ospf_convergence()
39 # Wait for OSPF convergence in each VRF. OSPF is run on
40 # R1 and R11 - R15.
41 # - test_pim_convergence()
42 # Wait for PIM convergence on all routers. PIM is run on
43 # R1 and R11 - R15.
44 # - test_mcast_acl_1():
45 # Test 1st ACL entry 239.100.0.0/28 with 239.100.0.1 which
46 # should use R11 as RP
47 # Stop multicast after verification
48 # - test_mcast_acl_2():
49 # Test 2nd ACL entry 239.100.0.17/32 with 239.100.0.17 which
50 # should use R12 as RP
51 # Stop multicast after verification
52 # - test_mcast_acl_3():
53 # Test 3rd ACL entry 239.100.0.32/27 with 239.100.0.32 which
54 # should use R13 as RP
55 # Stop multicast after verification
56 # - test_mcast_acl_4():
57 # Test 4th ACL entry 239.100.0.128/25 with 239.100.0.255 which
58 # should use R14 as RP
59 # Stop multicast after verification
60 # - test_mcast_acl_5():
61 # Test 5th ACL entry 239.100.0.96/28 with 239.100.0.97 which
62 # should use R14 as RP
63 # Stop multicast after verification
64 # - test_mcast_acl_6():
65 # Test 6th ACL entry 239.100.0.64/28 with 239.100.0.70 which
66 # should use R15 as RP
67 # Stop multicast after verification
68 # - teardown_module()
69 # shutdown topology
70 #
71
72 # XXX clean up in later commit to avoid conflict on rebase
73 # pylint: disable=C0413
74 TOPOLOGY = """
75 +----------+
76 | Host H2 |
77 | Source |
78 +----------+
79 .2 |
80 +-----------+ | +----------+
81 | | .1 | .11 | Host R11 |
82 +---------+ | R1 |---------+--------| PIM RP |
83 | Host H1 | 192.168.100.0/24 | | 192.168.101.0/24 +----------+
84 | receive |------------------| uses ACLs | | +----------+
85 |IGMP JOIN| .10 .1 | to pick | | .12 | Host R12 |
86 +---------+ | RP | +--------| PIM RP |
87 | | | +----------+
88 +-----------+ | +----------+
89 | .13 | Host R13 |
90 +--------| PIM RP |
91 | +----------+
92 | +----------+
93 | .14 | Host R14 |
94 +--------| PIM RP |
95 | +----------+
96 | +----------+
97 | .15 | Host R15 |
98 +--------| PIM RP |
99 +----------+
100 """
101
102 import json
103 import functools
104 import os
105 import sys
106 import pytest
107
108 # Save the Current Working Directory to find configuration files.
109 CWD = os.path.dirname(os.path.realpath(__file__))
110 sys.path.append(os.path.join(CWD, "../"))
111
112 # pylint: disable=C0413
113 # Import topogen and topotest helpers
114 from lib import topotest
115 from lib.topogen import Topogen, TopoRouter, get_topogen
116 from lib.topolog import logger
117
118 # Required to instantiate the topology builder class.
119 from lib.pim import McastTesterHelper
120
121 pytestmark = [pytest.mark.pimd, pytest.mark.ospfd]
122
123
124 def build_topo(tgen):
125 for hostNum in range(1, 3):
126 tgen.add_router("h{}".format(hostNum))
127
128 # Create the main router
129 tgen.add_router("r1")
130
131 # Create the PIM RP routers
132 for rtrNum in range(11, 16):
133 tgen.add_router("r{}".format(rtrNum))
134
135 # Setup Switches and connections
136 for swNum in range(1, 3):
137 tgen.add_switch("sw{}".format(swNum))
138
139 # Add connections H1 to R1 switch sw1
140 tgen.gears["h1"].add_link(tgen.gears["sw1"])
141 tgen.gears["r1"].add_link(tgen.gears["sw1"])
142
143 # Add connections R1 to R1x switch sw2
144 tgen.gears["r1"].add_link(tgen.gears["sw2"])
145 tgen.gears["h2"].add_link(tgen.gears["sw2"])
146 tgen.gears["r11"].add_link(tgen.gears["sw2"])
147 tgen.gears["r12"].add_link(tgen.gears["sw2"])
148 tgen.gears["r13"].add_link(tgen.gears["sw2"])
149 tgen.gears["r14"].add_link(tgen.gears["sw2"])
150 tgen.gears["r15"].add_link(tgen.gears["sw2"])
151
152
153 #####################################################
154 #
155 # Tests starting
156 #
157 #####################################################
158
159
160 def setup_module(module):
161 logger.info("PIM RP ACL Topology: \n {}".format(TOPOLOGY))
162
163 tgen = Topogen(build_topo, module.__name__)
164 tgen.start_topology()
165
166 # Starting Routers
167 router_list = tgen.routers()
168
169 for rname, router in router_list.items():
170 logger.info("Loading router %s" % rname)
171 router.load_config(
172 TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
173 )
174 if rname[0] != "h":
175 # Only load ospf on routers, not on end hosts
176 router.load_config(
177 TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
178 )
179 router.load_config(
180 TopoRouter.RD_PIM, os.path.join(CWD, "{}/pimd.conf".format(rname))
181 )
182 tgen.start_router()
183
184
185 def teardown_module(module):
186 tgen = get_topogen()
187 tgen.stop_topology()
188
189
190 def test_ospf_convergence():
191 "Test for OSPFv2 convergence"
192 tgen = get_topogen()
193
194 # Skip if previous fatal error condition is raised
195 if tgen.routers_have_failure():
196 pytest.skip(tgen.errors)
197
198 logger.info("Checking OSPFv2 convergence on router r1")
199
200 router = tgen.gears["r1"]
201 reffile = os.path.join(CWD, "r1/ospf_neighbor.json")
202 expected = json.loads(open(reffile).read())
203
204 test_func = functools.partial(
205 topotest.router_json_cmp, router, "show ip ospf neighbor json", expected
206 )
207 _, res = topotest.run_and_expect(test_func, None, count=60, wait=2)
208 assertmsg = "OSPF router R1 did not converge"
209 assert res is None, assertmsg
210
211
212 def test_pim_convergence():
213 "Test for PIM convergence"
214 tgen = get_topogen()
215
216 # Skip if previous fatal error condition is raised
217 if tgen.routers_have_failure():
218 pytest.skip(tgen.errors)
219
220 logger.info("Checking PIM convergence on router r1")
221
222 router = tgen.gears["r1"]
223 reffile = os.path.join(CWD, "r1/pim_neighbor.json")
224 expected = json.loads(open(reffile).read())
225
226 test_func = functools.partial(
227 topotest.router_json_cmp, router, "show ip pim neighbor json", expected
228 )
229 _, res = topotest.run_and_expect(test_func, None, count=60, wait=2)
230 assertmsg = "PIM router R1 did not converge"
231 assert res is None, assertmsg
232
233
234 def check_mcast_entry(entry, mcastaddr, pimrp):
235 "Helper function to check RP"
236 tgen = get_topogen()
237
238 logger.info(
239 "Testing PIM RP selection for ACL {} entry using {}".format(entry, mcastaddr)
240 )
241
242 with McastTesterHelper(tgen) as helper:
243 helper.run("h2", ["--send=0.7", mcastaddr, "h2-eth0"])
244 helper.run("h1", [mcastaddr, "h1-eth0"])
245
246 logger.info("mcast join and source for {} started".format(mcastaddr))
247
248 # tgen.mininet_cli()
249
250 router = tgen.gears["r1"]
251 reffile = os.path.join(CWD, "r1/acl_{}_pim_join.json".format(entry))
252 expected = json.loads(open(reffile).read())
253
254 logger.info("verifying pim join on r1 for {}".format(mcastaddr))
255 test_func = functools.partial(
256 topotest.router_json_cmp, router, "show ip pim join json", expected
257 )
258 _, res = topotest.run_and_expect(test_func, None, count=60, wait=2)
259 assertmsg = "PIM router r1 did not show join status"
260 assert res is None, assertmsg
261
262 logger.info("verifying pim join on PIM RP {} for {}".format(pimrp, mcastaddr))
263 router = tgen.gears[pimrp]
264 reffile = os.path.join(CWD, "{}/acl_{}_pim_join.json".format(pimrp, entry))
265 expected = json.loads(open(reffile).read())
266
267 test_func = functools.partial(
268 topotest.router_json_cmp, router, "show ip pim join json", expected
269 )
270 _, res = topotest.run_and_expect(test_func, None, count=60, wait=2)
271 assertmsg = "PIM router {} did not get selected as the PIM RP".format(pimrp)
272 assert res is None, assertmsg
273
274 return
275
276
277 def test_mcast_acl_1():
278 "Test 1st ACL entry 239.100.0.0/28 with 239.100.0.1"
279 tgen = get_topogen()
280
281 # Skip if previous fatal error condition is raised
282 if tgen.routers_have_failure():
283 pytest.skip(tgen.errors)
284
285 check_mcast_entry(1, "239.100.0.1", "r11")
286
287
288 def test_mcast_acl_2():
289 "Test 2nd ACL entry 239.100.0.17/32 with 239.100.0.17"
290 tgen = get_topogen()
291
292 # Skip if previous fatal error condition is raised
293 if tgen.routers_have_failure():
294 pytest.skip(tgen.errors)
295
296 check_mcast_entry(2, "239.100.0.17", "r12")
297
298
299 def test_mcast_acl_3():
300 "Test 3rd ACL entry 239.100.0.32/27 with 239.100.0.32"
301 tgen = get_topogen()
302
303 # Skip if previous fatal error condition is raised
304 if tgen.routers_have_failure():
305 pytest.skip(tgen.errors)
306
307 check_mcast_entry(3, "239.100.0.32", "r13")
308
309
310 def test_mcast_acl_4():
311 "Test 4th ACL entry 239.100.0.128/25 with 239.100.0.255"
312 tgen = get_topogen()
313
314 # Skip if previous fatal error condition is raised
315 if tgen.routers_have_failure():
316 pytest.skip(tgen.errors)
317
318 check_mcast_entry(4, "239.100.0.255", "r14")
319
320
321 def test_mcast_acl_5():
322 "Test 5th ACL entry 239.100.0.96/28 with 239.100.0.97"
323 tgen = get_topogen()
324
325 # Skip if previous fatal error condition is raised
326 if tgen.routers_have_failure():
327 pytest.skip(tgen.errors)
328
329 check_mcast_entry(5, "239.100.0.97", "r14")
330
331
332 def test_mcast_acl_6():
333 "Test 6th ACL entry 239.100.0.64/28 with 239.100.0.70"
334 tgen = get_topogen()
335
336 # Skip if previous fatal error condition is raised
337 if tgen.routers_have_failure():
338 pytest.skip(tgen.errors)
339
340 check_mcast_entry(6, "239.100.0.70", "r15")
341
342
343 if __name__ == "__main__":
344 args = ["-s"] + sys.argv[1:]
345 sys.exit(pytest.main(args))