]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py
Merge pull request #12816 from gpnaveen/stc_rte_err_msg
[mirror_frr.git] / tests / topotests / multicast_pim6_sm_topo1 / test_multicast_pim6_sm2.py
CommitLineData
7ce53cf7
KK
1#!/usr/bin/env python
2# SPDX-License-Identifier: ISC
3
4#
5# Copyright (c) 2022 by VMware, Inc. ("VMware")
6# Used Copyright (c) 2018 by Network Device Education Foundation,
7# Inc. ("NetDEF") in this file.
8#
9
10"""
11Following tests are covered to test multicast pim6 sm:
12
13Test steps
14- Create topology (setup module)
15- Bring up topology
16
17Following tests are covered:
181. Verify (*,G) and (S,G) entry populated again after clear the
19PIM nbr and mroute from FRR node
202. Verify SPT switchover working when RPT and SPT path is
21different
22"""
23
24import os
25import sys
26import json
27import time
28import datetime
29import pytest
30
31# Save the Current Working Directory to find configuration files.
32CWD = os.path.dirname(os.path.realpath(__file__))
33sys.path.append(os.path.join(CWD, "../"))
34sys.path.append(os.path.join(CWD, "../lib/"))
35
36# Required to instantiate the topology builder class.
37
38# pylint: disable=C0413
39# Import topogen and topotest helpers
40from lib.topogen import Topogen, get_topogen
41
42from lib.common_config import (
43 start_topology,
44 write_test_header,
45 write_test_footer,
46 step,
47 reset_config_on_routers,
48 shutdown_bringup_interface,
49 start_router,
50 stop_router,
51 create_static_routes,
52 required_linux_kernel_version,
53 socat_send_mld_join,
54 socat_send_pim6_traffic,
55 get_frr_ipv6_linklocal,
56)
57from lib.bgp import create_router_bgp
58from lib.pim import (
59 create_pim_config,
60 create_mld_config,
61 verify_mld_groups,
62 verify_mroutes,
63 clear_pim6_interface_traffic,
64 verify_upstream_iif,
65 clear_pim6_mroute,
66 verify_pim_interface_traffic,
67 verify_pim_state,
68 McastTesterHelper,
69 verify_pim_join,
70 verify_mroute_summary,
71 verify_pim_nexthop,
72 verify_sg_traffic,
73 verify_mld_config,
74)
75
76from lib.topolog import logger
77from lib.topojson import build_config_from_json
78
79# Global variables
80GROUP_RANGE = "ff00::/8"
81
82GROUP_RANGE_1 = [
83 "ffaa::1/128",
84 "ffaa::2/128",
85 "ffaa::3/128",
86 "ffaa::4/128",
87 "ffaa::5/128",
88]
89MLD_JOIN_RANGE_1 = ["ffaa::1", "ffaa::2", "ffaa::3", "ffaa::4", "ffaa::5"]
90
91GROUP_RANGE_2 = [
92 "ffbb::1/128",
93 "ffbb::2/128",
94 "ffbb::3/128",
95 "ffbb::4/128",
96 "ffbb::5/128",
97]
98MLD_JOIN_RANGE_2 = ["ffbb::1", "ffbb::2", "ffbb::3", "ffbb::4", "ffbb::5"]
99GROUP_RANGE_3 = [
100 "ffcc::1/128",
101 "ffcc::2/128",
102 "ffcc::3/128",
103 "ffcc::4/128",
104 "ffcc::5/128",
105]
106MLD_JOIN_RANGE_3 = ["ffcc::1", "ffcc::2", "ffcc::3", "ffcc::4", "ffcc::5"]
107
108HELLO_TIMER = 1
109HOLD_TIMER = 3
110PREFERRED_NEXT_HOP = "link_local"
111ASSERT_MSG = "Testcase {} : Failed Error: {}"
112
113pytestmark = [pytest.mark.pim6d]
114
115
116def setup_module(mod):
117 """
118 Sets up the pytest environment
119
120 * `mod`: module name
121 """
122
123 # Required linux kernel version for this suite to run.
124 result = required_linux_kernel_version("4.19")
125 if result is not True:
126 pytest.skip("Kernel requirements are not met")
127
128 testsuite_run_time = time.asctime(time.localtime(time.time()))
129 logger.info("Testsuite start time: {}".format(testsuite_run_time))
130 logger.info("=" * 40)
131
132 logger.info("Running setup_module to create topology")
133
134 testdir = os.path.dirname(os.path.realpath(__file__))
135 json_file = "{}/multicast_pim6_sm_topo1.json".format(testdir)
136 tgen = Topogen(json_file, mod.__name__)
137 global topo
138 topo = tgen.json_topo
139 # ... and here it calls Mininet initialization functions.
140
141 # Starting topology, create tmp files which are loaded to routers
142 # to start deamons and then start routers
143 start_topology(tgen)
144
145 # Don"t run this test if we have any failure.
146 if tgen.routers_have_failure():
147 pytest.skip(tgen.errors)
148
149 # Creating configuration from JSON
150 build_config_from_json(tgen, tgen.json_topo)
151
152 # XXX Replace this using "with McastTesterHelper()... " in each test if possible.
153 global app_helper
154 app_helper = McastTesterHelper(tgen)
155
156 logger.info("Running setup_module() done")
157
158
159def teardown_module():
160 """Teardown the pytest environment"""
161
162 logger.info("Running teardown_module to delete topology")
163
164 tgen = get_topogen()
165
166 app_helper.cleanup()
167
168 # Stop toplogy and Remove tmp files
169 tgen.stop_topology()
170
171 logger.info(
172 "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
173 )
174 logger.info("=" * 40)
175
176
177#####################################################
178#
179# Local APIs
180#
181#####################################################
182
183
184def verify_state_incremented(state_before, state_after):
185 """
186 API to compare interface traffic state incrementing
187
188 Parameters
189 ----------
190 * `state_before` : State dictionary for any particular instance
191 * `state_after` : State dictionary for any particular instance
192 """
193
194 for router, state_data in state_before.items():
195 for state, value in state_data.items():
196 if state_before[router][state] >= state_after[router][state]:
197 errormsg = (
198 "[DUT: %s]: state %s value has not"
199 " incremented, Initial value: %s, "
200 "Current value: %s [FAILED!!]"
201 % (
202 router,
203 state,
204 state_before[router][state],
205 state_after[router][state],
206 )
207 )
208 return errormsg
209
210 logger.info(
211 "[DUT: %s]: State %s value is "
212 "incremented, Initial value: %s, Current value: %s"
213 " [PASSED!!]",
214 router,
215 state,
216 state_before[router][state],
217 state_after[router][state],
218 )
219
220 return True
221
222
223#####################################################
224#
225# Testcases
226#
227#####################################################
228
229
230def test_clear_mroute_and_verify_multicast_data_p0(request):
231 """
232 Verify (*,G) and (S,G) entry populated again after clear the
233 PIM nbr and mroute from FRR node
234 """
235 tgen = get_topogen()
236 tc_name = request.node.name
237 write_test_header(tc_name)
238
239 # Creating configuration from JSON
240 reset_config_on_routers(tgen)
241
242 # Don"t run this test if we have any failure.
243 if tgen.routers_have_failure():
244 pytest.skip(tgen.errors)
245
246 step("Configure static RP on r4 for group (ffcc::1-5)")
247 input_dict = {
248 "r4": {
249 "pim6": {
250 "rp": [
251 {
252 "rp_addr": topo["routers"]["r4"]["links"]["lo"]["ipv6"].split(
253 "/"
254 )[0],
255 "group_addr_range": GROUP_RANGE_1,
256 }
257 ]
258 }
259 }
260 }
261
262 result = create_pim_config(tgen, topo, input_dict)
263 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
264
265 step(
266 "Enable mld on FRR1 interface and send mld join ffaa::1 "
267 "to ffaa::5 from different interfaces"
268 )
269
270 step("send mld join (ffaa::1-5) to R1")
271 intf = topo["routers"]["i1"]["links"]["r1"]["interface"]
272 intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0]
273 result = socat_send_mld_join(
274 tgen, "i1", "UDP6-RECV", MLD_JOIN_RANGE_1, intf, intf_ip
275 )
276 assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
277
278 step("Send multicast traffic from FRR3 to all the receivers" "ffaa::1-5")
279
280 intf_ip = topo["routers"]["i2"]["links"]["r3"]["ipv6"].split("/")[0]
281 intf = topo["routers"]["i2"]["links"]["r3"]["interface"]
282 result = socat_send_pim6_traffic(tgen, "i2", "UDP6-SEND", MLD_JOIN_RANGE_1, intf)
283 assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
284
285 step("Clear the mroute on r1, wait for 5 sec")
286 result = clear_pim6_mroute(tgen, "r1")
287 assert result is True, "Testcase{}: Failed Error: {}".format(tc_name, result)
288
289 step(
290 "After clear ip mroute (*,g) entries are re-populated again"
291 " with same OIL and IIF, verify using 'show ipv6 mroute' and "
292 " 'show ipv6 pim upstream' "
293 )
294
295 source = topo["routers"]["i2"]["links"]["r3"]["ipv6"].split("/")[0]
296 input_dict = [
297 {
298 "dut": "r1",
299 "src_address": "*",
300 "iif": topo["routers"]["r1"]["links"]["r4"]["interface"],
301 "oil": topo["routers"]["r1"]["links"]["i1"]["interface"],
302 }
303 ]
304
305 for data in input_dict:
306 result = verify_mroutes(
307 tgen,
308 data["dut"],
309 data["src_address"],
310 MLD_JOIN_RANGE_1,
311 data["iif"],
312 data["oil"],
313 )
314 assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
315
316 step(
317 "Verify 'show ipv6 pim upstream' showing correct OIL and IIF"
318 " on all the nodes"
319 )
320 for data in input_dict:
321 result = verify_upstream_iif(
322 tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1
323 )
324 assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
325
326 step("Clear the mroute on r3, wait for 5 sec")
327 result = clear_pim6_mroute(tgen, "r3")
328 assert result is True, "Testcase{}: Failed Error: {}".format(tc_name, result)
329
330 step(
331 "Verify 'show ipv6 mroute' showing correct RPF and OIF"
332 " interface for (*,G) and (S,G) entries on all the nodes"
333 )
334
335 input_dict = [
336 {
337 "dut": "r3",
338 "src_address": source,
339 "iif": topo["routers"]["r3"]["links"]["i2"]["interface"],
340 "oil": topo["routers"]["r3"]["links"]["r2"]["interface"],
341 }
342 ]
343
344 for data in input_dict:
345 result = verify_mroutes(
346 tgen,
347 data["dut"],
348 data["src_address"],
349 MLD_JOIN_RANGE_1,
350 data["iif"],
351 data["oil"],
352 )
353 assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
354
355 step(
356 "Verify 'show ipv6 pim upstream' showing correct OIL and IIF"
357 " on all the nodes"
358 )
359 for data in input_dict:
360 result = verify_upstream_iif(
361 tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1
362 )
363 assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
364
365 step("Clear the mroute on r2, wait for 5 sec")
366 result = clear_pim6_mroute(tgen, "r2")
367 assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
368
369 step(
370 "Verify 'show ipv6 mroute' showing correct RPF and OIF"
371 " interface for (*,G) and (S,G) entries on all the nodes"
372 )
373
374 input_dict = [
375 {
376 "dut": "r2",
377 "src_address": source,
378 "iif": topo["routers"]["r2"]["links"]["r3"]["interface"],
379 "oil": topo["routers"]["r2"]["links"]["r1"]["interface"],
380 }
381 ]
382
383 for data in input_dict:
384 result = verify_mroutes(
385 tgen,
386 data["dut"],
387 data["src_address"],
388 MLD_JOIN_RANGE_1,
389 data["iif"],
390 data["oil"],
391 )
392 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
393
394 step(
395 "Verify 'show ipv6 pim upstream' showing correct OIL and IIF"
396 " on all the nodes"
397 )
398 for data in input_dict:
399 result = verify_upstream_iif(
400 tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1
401 )
402 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
403
404 step("Clear the mroute on r1, r3, wait for 5 sec")
405 result = clear_pim6_mroute(tgen, "r1")
406 assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
407
408 result = clear_pim6_mroute(tgen, "r3")
409 assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
410
411 step(
412 "Verify 'show ipv6 mroute' showing correct RPF and OIF"
413 " interface for (*,G) and (S,G) entries on all the nodes"
414 )
415
416 input_dict = [
417 {
418 "dut": "r1",
419 "src_address": "*",
420 "iif": topo["routers"]["r1"]["links"]["r4"]["interface"],
421 "oil": topo["routers"]["r1"]["links"]["i1"]["interface"],
422 },
423 {
424 "dut": "r3",
425 "src_address": source,
426 "iif": topo["routers"]["r3"]["links"]["i2"]["interface"],
427 "oil": topo["routers"]["r3"]["links"]["r2"]["interface"],
428 },
429 ]
430
431 for data in input_dict:
432 result = verify_mroutes(
433 tgen,
434 data["dut"],
435 data["src_address"],
436 MLD_JOIN_RANGE_1,
437 data["iif"],
438 data["oil"],
439 )
440 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
441
442 step(
443 "Verify 'show ipv6 pim upstream' showing correct OIL and IIF"
444 " on all the nodes"
445 )
446 for data in input_dict:
447 result = verify_upstream_iif(
448 tgen, data["dut"], data["iif"], data["src_address"], MLD_JOIN_RANGE_1
449 )
450 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
451
452 step(
453 "multicast traffic is resume for all the receivers using "
454 " 'show ip multicast' "
455 )
456 result = verify_sg_traffic(tgen, "r1", MLD_JOIN_RANGE_1, source, "ipv6")
457 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
458
459 write_test_footer(tc_name)
460
461
462def test_verify_SPT_switchover_when_RPT_and_SPT_path_is_different_p0(request):
463 """
464 Verify SPT switchover working when RPT and SPT path is
465 different
466 """
467
468 tgen = get_topogen()
469 tc_name = request.node.name
470 write_test_header(tc_name)
471
472 # Creating configuration from JSON
473 reset_config_on_routers(tgen)
474
475 # Don"t run this test if we have any failure.
476 if tgen.routers_have_failure():
477 pytest.skip(tgen.errors)
478
479 step("Configure static RP for (ffcc::1-5) and " "(ffbb::1-5) in r5")
480
481 _GROUP_RANGE = GROUP_RANGE_2 + GROUP_RANGE_3
482 _MLD_JOIN_RANGE = MLD_JOIN_RANGE_2 + MLD_JOIN_RANGE_3
483
484 input_dict = {
485 "r5": {
486 "pim6": {
487 "rp": [
488 {
489 "rp_addr": topo["routers"]["r5"]["links"]["lo"]["ipv6"].split(
490 "/"
491 )[0],
492 "group_addr_range": _GROUP_RANGE,
493 }
494 ]
495 }
496 }
497 }
498
499 result = create_pim_config(tgen, topo, input_dict)
500 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
501
502 step("send mld join (ffbb::1-5, ffcc::1-5) to R1")
503 intf = topo["routers"]["i1"]["links"]["r1"]["interface"]
504 intf_ip = topo["routers"]["i1"]["links"]["r1"]["ipv6"].split("/")[0]
505 result = socat_send_mld_join(
506 tgen, "i1", "UDP6-RECV", _MLD_JOIN_RANGE, intf, intf_ip
507 )
508 assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
509
510 step("registerRx and registerStopTx value before traffic sent")
511 intf_r5 = topo["routers"]["r5"]["links"]["r3"]["interface"]
512 state_dict = {"r5": {intf_r5: ["registerRx", "registerStopTx"]}}
513 state_before = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
514 assert isinstance(
515 state_before, dict
516 ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format(
517 tc_name, result
518 )
519
520 step(
521 "Send multicast traffic from FRR3 to all the receivers" "ffbb::1-5 , ffcc::1-5"
522 )
523 intf_ip = topo["routers"]["i2"]["links"]["r3"]["ipv6"].split("/")[0]
524 intf = topo["routers"]["i2"]["links"]["r3"]["interface"]
525 result = socat_send_pim6_traffic(tgen, "i2", "UDP6-SEND", _MLD_JOIN_RANGE, intf)
526 assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
527
528 step(
529 "Verify in FRR3 sending initial packet to RP using"
530 " 'show ipv6 mroute' and mroute OIL is towards RP."
531 )
532
533 source = topo["routers"]["i2"]["links"]["r3"]["ipv6"].split("/")[0]
534
535 r3_i2 = topo["routers"]["r3"]["links"]["i2"]["interface"]
536 r3_r5 = topo["routers"]["r3"]["links"]["r5"]["interface"]
537 r3_r2 = topo["routers"]["r3"]["links"]["r2"]["interface"]
538 r1_r2 = topo["routers"]["r1"]["links"]["r2"]["interface"]
539 r1_i1 = topo["routers"]["r1"]["links"]["i1"]["interface"]
540
541 result = verify_mroutes(tgen, "r3", source, _MLD_JOIN_RANGE, r3_i2, [r3_r5, r3_r2])
542 assert result is True, "Testcase {} : " "Failed Error: {}".format(tc_name, result)
543
544 result = verify_mroutes(tgen, "r3", source, _MLD_JOIN_RANGE, r3_i2, r3_r2)
545 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
546
547 step(
548 " After spt switchover traffic is flowing between"
549 " (LHR(FRR1)-FHR(FRR3)) and (S,G) OIL is updated toward FRR1"
550 " 'show mroute' and 'show pim upstream'"
551 )
552
553 input_dict = [
554 {"dut": "r3", "src_address": source, "iif": r3_i2, "oil": r3_r2},
555 {"dut": "r1", "src_address": source, "iif": r1_r2, "oil": r1_i1},
556 ]
557 for data in input_dict:
558 result = verify_mroutes(
559 tgen,
560 data["dut"],
561 data["src_address"],
562 _MLD_JOIN_RANGE,
563 data["iif"],
564 data["oil"],
565 )
566 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
567
568 for data in input_dict:
569 result = verify_upstream_iif(
570 tgen, data["dut"], data["iif"], data["src_address"], _MLD_JOIN_RANGE
571 )
572 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
573
574 step("Stop the traffic to all the receivers")
575 dut = "i2"
576 intf = topo["routers"]["i2"]["links"]["r3"]["interface"]
577 shutdown_bringup_interface(tgen, dut, intf, False)
578
579 step(
580 "Null register packet being send periodically from FRR3 to RP, "
581 "verify using show ipv6 mroute on RP, have (S, G) entries null OIL"
582 " 'show ipv6 mroute' and verify show ip pim interface traffic"
583 "(In RP Register msg should be received and Register stop should"
584 " be transmitted)"
585 )
586
587 result = verify_upstream_iif(
588 tgen, "r3", "Unknown", source, _MLD_JOIN_RANGE, joinState="NotJoined"
589 )
590 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
591
592 step("registerRx and registerStopTx value after traffic sent")
593 state_after = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
594 assert isinstance(
595 state_after, dict
596 ), "Testcase {} : Failed \n state_before is not dictionary \n " "Error: {}".format(
597 tc_name, result
598 )
599
600 result = verify_state_incremented(state_before, state_after)
601 assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
602
603 write_test_footer(tc_name)
604
605
606if __name__ == "__main__":
607 args = ["-s"] + sys.argv[1:]
608 sys.exit(pytest.main(args))