]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/lib/pim.py
tests: Add pytest.mark.snmp
[mirror_frr.git] / tests / topotests / lib / pim.py
CommitLineData
e8cd26fd 1# Copyright (c) 2019 by VMware, Inc. ("VMware")
2# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
3# ("NetDEF") in this file.
4#
5# Permission to use, copy, modify, and/or distribute this software
6# for any purpose with or without fee is hereby granted, provided
7# that the above copyright notice and this permission notice appear
8# in all copies.
9#
10# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
11# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
13# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
14# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
15# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
16# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
17# OF THIS SOFTWARE.
18
19import sys
20import os
21import re
22import datetime
23import traceback
24import pytest
25from time import sleep
26from copy import deepcopy
27from lib.topolog import logger
28
29# Import common_config to use commomnly used APIs
30from lib.common_config import (
31 create_common_configuration,
32 InvalidCLIError,
33 retry,
34 run_frr_cmd,
35)
36
37####
38CWD = os.path.dirname(os.path.realpath(__file__))
39
40
41def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True):
42 """
43 API to configure pim on router
44
45 Parameters
46 ----------
47 * `tgen` : Topogen object
48 * `topo` : json file data
49 * `input_dict` : Input dict data, required when configuring from
50 testcase
51 * `build` : Only for initial setup phase this is set as True.
52
53 Usage
54 -----
55 input_dict = {
56 "r1": {
57 "pim": {
58 "disable" : ["l1-i1-eth1"],
59 "rp": [{
60 "rp_addr" : "1.0.3.17".
61 "keep-alive-timer": "100"
62 "group_addr_range": ["224.1.1.0/24", "225.1.1.0/24"]
63 "prefix-list": "pf_list_1"
64 "delete": True
65 }]
66 }
67 }
68 }
69
70
71 Returns
72 -------
73 True or False
74 """
75 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
76 result = False
77 if not input_dict:
78 input_dict = deepcopy(topo)
79 else:
80 topo = topo["routers"]
81 input_dict = deepcopy(input_dict)
82 for router in input_dict.keys():
83 result = _enable_disable_pim(tgen, topo, input_dict, router, build)
84
85 if "pim" not in input_dict[router]:
86 logger.debug("Router %s: 'pim' is not present in " "input_dict", router)
87 continue
88
89 if result is True:
90 if "rp" not in input_dict[router]["pim"]:
91 continue
92
93 result = _create_pim_config(
94 tgen, topo, input_dict, router, build, load_config
95 )
96 if result is not True:
97 return False
98
99 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
100 return result
101
102
103def _create_pim_config(tgen, topo, input_dict, router, build=False, load_config=False):
104 """
105 Helper API to create pim configuration.
106
107 Parameters
108 ----------
109 * `tgen` : Topogen object
110 * `topo` : json file data
111 * `input_dict` : Input dict data, required when configuring from testcase
112 * `router` : router id to be configured.
113 * `build` : Only for initial setup phase this is set as True.
114
115 Returns
116 -------
117 True or False
118 """
119
120 result = False
121 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
122 try:
123
124 pim_data = input_dict[router]["pim"]
125
126 for dut in tgen.routers():
127 if "pim" not in input_dict[router]:
128 continue
129
130 for destLink, data in topo[dut]["links"].items():
131 if "pim" not in data:
132 continue
133
134 if "rp" in pim_data:
135 config_data = []
136 rp_data = pim_data["rp"]
137
138 for rp_dict in deepcopy(rp_data):
139 # ip address of RP
140 if "rp_addr" not in rp_dict and build:
141 logger.error(
142 "Router %s: 'ip address of RP' not "
143 "present in input_dict/JSON",
144 router,
145 )
146
147 return False
148 rp_addr = rp_dict.setdefault("rp_addr", None)
149
150 # Keep alive Timer
151 keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None)
152
153 # Group Address range to cover
154 if "group_addr_range" not in rp_dict and build:
155 logger.error(
156 "Router %s:'Group Address range to cover'"
157 " not present in input_dict/JSON",
158 router,
159 )
160
161 return False
162 group_addr_range = rp_dict.setdefault("group_addr_range", None)
163
164 # Group prefix-list filter
165 prefix_list = rp_dict.setdefault("prefix_list", None)
166
167 # Delete rp config
168 del_action = rp_dict.setdefault("delete", False)
169
170 if keep_alive_timer:
171 cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer)
172 config_data.append(cmd)
173
174 if del_action:
175 cmd = "no {}".format(cmd)
176 config_data.append(cmd)
177
178 if rp_addr:
179 if group_addr_range:
180 if type(group_addr_range) is not list:
181 group_addr_range = [group_addr_range]
182
183 for grp_addr in group_addr_range:
184 cmd = "ip pim rp {} {}".format(rp_addr, grp_addr)
185 config_data.append(cmd)
186
187 if del_action:
188 cmd = "no {}".format(cmd)
189 config_data.append(cmd)
190
191 if prefix_list:
192 cmd = "ip pim rp {} prefix-list {}".format(
193 rp_addr, prefix_list
194 )
195 config_data.append(cmd)
196
197 if del_action:
198 cmd = "no {}".format(cmd)
199 config_data.append(cmd)
200
201 result = create_common_configuration(
202 tgen, dut, config_data, "pim", build, load_config
203 )
204 if result is not True:
205 return False
206
207 except InvalidCLIError:
208 # Traceback
209 errormsg = traceback.format_exc()
210 logger.error(errormsg)
211 return errormsg
212
213 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
214 return result
215
216
217def create_igmp_config(tgen, topo, input_dict=None, build=False):
218 """
219 API to configure igmp on router
220
221 Parameters
222 ----------
223 * `tgen` : Topogen object
224 * `topo` : json file data
225 * `input_dict` : Input dict data, required when configuring from
226 testcase
227 * `build` : Only for initial setup phase this is set as True.
228
229 Usage
230 -----
231 input_dict = {
232 "r1": {
233 "igmp": {
234 "interfaces": {
235 "r1-r0-eth0" :{
236 "igmp":{
237 "version": "2",
238 "delete": True
239 "query": {
240 "query-interval" : 100,
241 "query-max-response-time": 200
242 }
243 }
244 }
245 }
246 }
247 }
248 }
249
250 Returns
251 -------
252 True or False
253 """
254 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
255 result = False
256 if not input_dict:
257 input_dict = deepcopy(topo)
258 else:
259 topo = topo["routers"]
260 input_dict = deepcopy(input_dict)
261 for router in input_dict.keys():
262 if "igmp" not in input_dict[router]:
263 logger.debug("Router %s: 'igmp' is not present in " "input_dict", router)
264 continue
265
266 igmp_data = input_dict[router]["igmp"]
267
268 if "interfaces" in igmp_data:
269 config_data = []
270 intf_data = igmp_data["interfaces"]
271
272 for intf_name in intf_data.keys():
273 cmd = "interface {}".format(intf_name)
274 config_data.append(cmd)
275 protocol = "igmp"
276 del_action = intf_data[intf_name]["igmp"].setdefault("delete", False)
277 cmd = "ip igmp"
278 if del_action:
279 cmd = "no {}".format(cmd)
280 config_data.append(cmd)
281
282 del_attr = intf_data[intf_name]["igmp"].setdefault("delete_attr", False)
283 for attribute, data in intf_data[intf_name]["igmp"].items():
284 if attribute == "version":
285 cmd = "ip {} {} {}".format(protocol, attribute, data)
286 if del_action:
287 cmd = "no {}".format(cmd)
288 config_data.append(cmd)
289
290 if attribute == "join":
291 for group in data:
292 cmd = "ip {} {} {}".format(protocol, attribute, group)
293 if del_attr:
294 cmd = "no {}".format(cmd)
295 config_data.append(cmd)
296
297 if attribute == "query":
298 for query, value in data.items():
299 if query != "delete":
300 cmd = "ip {} {} {}".format(protocol, query, value)
301
302 if "delete" in intf_data[intf_name][protocol]["query"]:
303 cmd = "no {}".format(cmd)
304
305 config_data.append(cmd)
306 try:
307
308 result = create_common_configuration(
309 tgen, router, config_data, "interface_config", build=build
310 )
311 except InvalidCLIError:
312 errormsg = traceback.format_exc()
313 logger.error(errormsg)
314 return errormsg
315
316 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
317 return result
318
319
320def _enable_disable_pim(tgen, topo, input_dict, router, build=False):
321 """
322 Helper API to enable or disable pim on interfaces
323
324 Parameters
325 ----------
326 * `tgen` : Topogen object
327 * `topo` : json file data
328 * `input_dict` : Input dict data, required when configuring from testcase
329 * `router` : router id to be configured.
330 * `build` : Only for initial setup phase this is set as True.
331
332 Returns
333 -------
334 True or False
335 """
336 result = False
337 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
338 try:
339 config_data = []
340
341 enable_flag = True
342 # Disable pim on interface
343 if "pim" in input_dict[router]:
344 if "disable" in input_dict[router]["pim"]:
345 enable_flag = False
346 interfaces = input_dict[router]["pim"]["disable"]
347
348 if type(interfaces) is not list:
349 interfaces = [interfaces]
350
351 for interface in interfaces:
352 cmd = "interface {}".format(interface)
353 config_data.append(cmd)
354 config_data.append("no ip pim")
355
356 # Enable pim on interface
357 if enable_flag:
358 for destRouterLink, data in sorted(topo[router]["links"].items()):
359 if "pim" in data and data["pim"] == "enable":
360
361 # Loopback interfaces
362 if "type" in data and data["type"] == "loopback":
363 interface_name = destRouterLink
364 else:
365 interface_name = data["interface"]
366
367 cmd = "interface {}".format(interface_name)
368 config_data.append(cmd)
369 config_data.append("ip pim")
370
371 result = create_common_configuration(
372 tgen, router, config_data, "interface_config", build=build
373 )
374 if result is not True:
375 return False
376
377 except InvalidCLIError:
378 # Traceback
379 errormsg = traceback.format_exc()
380 logger.error(errormsg)
381 return errormsg
382
383 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
384 return result
385
386
387def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping):
388 """
389 Add physical interfaces tp RP for all the RPs
390
391 Parameters
392 ----------
393 * `tgen` : Topogen object
394 * `topo` : json file data
395 * `interface` : RP interface
396 * `rp` : rp for given topology
397 * `rp_mapping` : dictionary of all groups and RPs
398
399 Returns
400 -------
401 True or False
402 """
403 result = False
404 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
405
406 try:
407 config_data = []
408
409 for group, rp_list in rp_mapping.items():
410 for _rp in rp_list:
411 config_data.append("interface {}".format(interface))
412 config_data.append("ip address {}".format(_rp))
413 config_data.append("ip pim")
414
415 result = create_common_configuration(
416 tgen, rp, config_data, "interface_config"
417 )
418 if result is not True:
419 return False
420
421 except InvalidCLIError:
422 # Traceback
423 errormsg = traceback.format_exc()
424 logger.error(errormsg)
425 return errormsg
426
427 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
428 return result
429
430
431def find_rp_details(tgen, topo):
432 """
433 Find who is RP in topology and returns list of RPs
434
435 Parameters:
436 -----------
437 * `tgen` : Topogen object
438 * `topo` : json file data
439
440 returns:
441 --------
442 errormsg or True
443 """
444
445 rp_details = {}
446
447 router_list = tgen.routers()
448 topo_data = topo["routers"]
449
450 for router in router_list.keys():
451
452 if "pim" not in topo_data[router]:
453 continue
454
455 pim_data = topo_data[router]["pim"]
456 if "rp" in pim_data:
457 rp_data = pim_data["rp"]
458 for rp_dict in rp_data:
459 # ip address of RP
460 rp_addr = rp_dict["rp_addr"]
461
462 for link, data in topo["routers"][router]["links"].items():
463 if data["ipv4"].split("/")[0] == rp_addr:
464 rp_details[router] = rp_addr
465
466 return rp_details
467
468
469def configure_pim_force_expire(tgen, topo, input_dict, build=False):
470 """
471 Helper API to create pim configuration.
472
473 Parameters
474 ----------
475 * `tgen` : Topogen object
476 * `topo` : json file data
477 * `input_dict` : Input dict data, required when configuring from testcase
478 * `build` : Only for initial setup phase this is set as True.
479
480 Usage
481 -----
482 input_dict ={
483 "l1": {
484 "pim": {
485 "force_expire":{
486 "10.0.10.1": ["255.1.1.1"]
487 }
488 }
489 }
490 }
491
492 result = create_pim_config(tgen, topo, input_dict)
493
494 Returns
495 -------
496 True or False
497 """
498
499 result = False
500 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
501 try:
502
503 for dut in input_dict.keys():
504 if "pim" not in input_dict[dut]:
505 continue
506
507 pim_data = input_dict[dut]["pim"]
508
509 if "force_expire" in pim_data:
510 config_data = []
511 force_expire_data = pim_data["force_expire"]
512
513 for source, groups in force_expire_data.items():
514 if type(groups) is not list:
515 groups = [groups]
516
517 for group in groups:
518 cmd = "ip pim force-expire source {} group {}".format(
519 source, group
520 )
521 config_data.append(cmd)
522
523 result = create_common_configuration(
524 tgen, dut, config_data, "pim", build=build
525 )
526 if result is not True:
527 return False
528
529 except InvalidCLIError:
530 # Traceback
531 errormsg = traceback.format_exc()
532 logger.error(errormsg)
533 return errormsg
534
535 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
536 return result
537
538
539#############################################
540# Verification APIs
541#############################################
eab72dc8 542@retry(attempts=6, wait=2, return_is_str=True)
543def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None):
e8cd26fd 544 """
545 Verify all PIM neighbors are up and running, config is verified
546 using "show ip pim neighbor" cli
547
548 Parameters
549 ----------
550 * `tgen`: topogen object
551 * `topo` : json file data
552 * `dut` : dut info
553 * `iface` : link for which PIM nbr need to check
eab72dc8 554 * `nbr_ip` : neighbor ip of interface
e8cd26fd 555
556 Usage
557 -----
eab72dc8 558 result = verify_pim_neighbors(tgen, topo, dut, iface=ens192, nbr_ip=20.1.1.2)
e8cd26fd 559
560 Returns
561 -------
562 errormsg(str) or True
563 """
564
565 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
566
567 for router in tgen.routers():
568 if dut is not None and dut != router:
569 continue
570
571 rnode = tgen.routers()[router]
572 show_ip_pim_neighbor_json = rnode.vtysh_cmd(
573 "show ip pim neighbor json", isjson=True
574 )
575
576 for destLink, data in topo["routers"][router]["links"].items():
577 if iface is not None and iface != data["interface"]:
578 continue
579
580 if "type" in data and data["type"] == "loopback":
581 continue
582
583 if "pim" not in data:
584 continue
585
586 if "pim" in data and data["pim"] == "enable":
587 local_interface = data["interface"]
588
589 if "-" in destLink:
590 # Spliting and storing destRouterLink data in tempList
591 tempList = destLink.split("-")
592
593 # destRouter
594 destLink = tempList.pop(0)
595
596 # Current Router Link
597 tempList.insert(0, router)
598 curRouter = "-".join(tempList)
599 else:
600 curRouter = router
601 if destLink not in topo["routers"]:
602 continue
603 data = topo["routers"][destLink]["links"][curRouter]
604 if "type" in data and data["type"] == "loopback":
605 continue
606
607 if "pim" not in data:
608 continue
609
610 logger.info("[DUT: %s]: Verifying PIM neighbor status:", router)
611
612 if "pim" in data and data["pim"] == "enable":
613 pim_nh_intf_ip = data["ipv4"].split("/")[0]
614
615 # Verifying PIM neighbor
616 if local_interface in show_ip_pim_neighbor_json:
617 if show_ip_pim_neighbor_json[local_interface]:
618 if (
619 show_ip_pim_neighbor_json[local_interface][pim_nh_intf_ip][
620 "neighbor"
621 ]
622 != pim_nh_intf_ip
623 ):
624 errormsg = (
625 "[DUT %s]: Local interface: %s, PIM"
626 " neighbor check failed "
627 "Expected neighbor: %s, Found neighbor:"
628 " %s"
629 % (
630 router,
631 local_interface,
632 pim_nh_intf_ip,
633 show_ip_pim_neighbor_json[local_interface][
634 pim_nh_intf_ip
635 ]["neighbor"],
636 )
637 )
638 return errormsg
639
640 logger.info(
641 "[DUT %s]: Local interface: %s, Found"
642 " expected PIM neighbor %s",
643 router,
644 local_interface,
645 pim_nh_intf_ip,
646 )
647 else:
648 errormsg = (
649 "[DUT %s]: Local interface: %s, and"
650 "interface ip: %s is not found in "
651 "PIM neighbor " % (router, local_interface, pim_nh_intf_ip)
652 )
653 return errormsg
654 else:
655 errormsg = (
656 "[DUT %s]: Local interface: %s, is not "
657 "present in PIM neighbor " % (router, local_interface)
658 )
659 return errormsg
660
661 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
662 return True
663
664
665@retry(attempts=21, wait=2, return_is_str=True)
666def verify_igmp_groups(tgen, dut, interface, group_addresses):
667 """
668 Verify IGMP groups are received from an intended interface
669 by running "show ip igmp groups" command
670
671 Parameters
672 ----------
673 * `tgen`: topogen object
674 * `dut`: device under test
675 * `interface`: interface, from which IGMP groups would be received
676 * `group_addresses`: IGMP group address
677
678 Usage
679 -----
680 dut = "r1"
681 interface = "r1-r0-eth0"
682 group_address = "225.1.1.1"
683 result = verify_igmp_groups(tgen, dut, interface, group_address)
684
685 Returns
686 -------
687 errormsg(str) or True
688 """
689
690 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
691
692 if dut not in tgen.routers():
693 return False
694
695 rnode = tgen.routers()[dut]
696
697 logger.info("[DUT: %s]: Verifying IGMP groups received:", dut)
698 show_ip_igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
699
700 if type(group_addresses) is not list:
701 group_addresses = [group_addresses]
702
703 if interface in show_ip_igmp_json:
704 show_ip_igmp_json = show_ip_igmp_json[interface]["groups"]
705 else:
706 errormsg = (
707 "[DUT %s]: Verifying IGMP group received"
708 " from interface %s [FAILED]!! " % (dut, interface)
709 )
710 return errormsg
711
712 found = False
713 for grp_addr in group_addresses:
714 for index in show_ip_igmp_json:
715 if index["group"] == grp_addr:
716 found = True
717 break
718 if found is not True:
719 errormsg = (
720 "[DUT %s]: Verifying IGMP group received"
721 " from interface %s [FAILED]!! "
722 " Expected not found: %s" % (dut, interface, grp_addr)
723 )
724 return errormsg
725
726 logger.info(
727 "[DUT %s]: Verifying IGMP group %s received "
728 "from interface %s [PASSED]!! ",
729 dut,
730 grp_addr,
731 interface,
732 )
733
734 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
735 return True
736
737
738@retry(attempts=31, wait=2, return_is_str=True)
739def verify_upstream_iif(
740 tgen, dut, iif, src_address, group_addresses, joinState=None, refCount=1
741):
742 """
743 Verify upstream inbound interface is updated correctly
744 by running "show ip pim upstream" cli
745
746 Parameters
747 ----------
748 * `tgen`: topogen object
749 * `dut`: device under test
750 * `iif`: inbound interface
751 * `src_address`: source address
752 * `group_addresses`: IGMP group address
753 * `joinState`: upstream join state
754 * `refCount`: refCount value
755
756 Usage
757 -----
758 dut = "r1"
759 iif = "r1-r0-eth0"
760 src_address = "*"
761 group_address = "225.1.1.1"
762 result = verify_upstream_iif(tgen, dut, iif, src_address, group_address,
763 state, refCount)
764
765 Returns
766 -------
767 errormsg(str) or True
768 """
769
770 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
771
772 if dut not in tgen.routers():
773 return False
774
775 rnode = tgen.routers()[dut]
776
777 logger.info(
778 "[DUT: %s]: Verifying upstream Inbound Interface" " for IGMP groups received:",
779 dut,
780 )
781 show_ip_pim_upstream_json = run_frr_cmd(
782 rnode, "show ip pim upstream json", isjson=True
783 )
784
785 if type(group_addresses) is not list:
786 group_addresses = [group_addresses]
787
788 if type(iif) is not list:
789 iif = [iif]
790
791 for grp_addr in group_addresses:
792 # Verify group address
793 if grp_addr not in show_ip_pim_upstream_json:
794 errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
795 dut,
796 grp_addr,
797 )
798 return errormsg
799 group_addr_json = show_ip_pim_upstream_json[grp_addr]
800
801 # Verify source address
802 if src_address not in group_addr_json:
803 errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
804 dut,
805 src_address,
806 grp_addr,
807 )
808 return errormsg
809
810 # Verify Inbound Interface
811 found = False
812 for in_interface in iif:
813 if group_addr_json[src_address]["inboundInterface"] == in_interface:
814 if refCount > 0:
815 logger.info(
816 "[DUT %s]: Verifying refCount "
817 "for (%s,%s) [PASSED]!! "
818 " Found Expected: %s",
819 dut,
820 src_address,
821 grp_addr,
822 group_addr_json[src_address]["refCount"],
823 )
824 found = True
825 if found:
826 if joinState is None:
827 if group_addr_json[src_address]["joinState"] != "Joined":
828 errormsg = (
829 "[DUT %s]: Verifying iif "
830 "(Inbound Interface) for (%s,%s) and"
831 " joinState :%s [FAILED]!! "
832 " Expected: %s, Found: %s"
833 % (
834 dut,
835 src_address,
836 grp_addr,
837 group_addr_json[src_address]["joinState"],
838 in_interface,
839 group_addr_json[src_address]["inboundInterface"],
840 )
841 )
842 return errormsg
843
844 elif group_addr_json[src_address]["joinState"] != joinState:
845 errormsg = (
846 "[DUT %s]: Verifying iif "
847 "(Inbound Interface) for (%s,%s) and"
848 " joinState :%s [FAILED]!! "
849 " Expected: %s, Found: %s"
850 % (
851 dut,
852 src_address,
853 grp_addr,
854 group_addr_json[src_address]["joinState"],
855 in_interface,
856 group_addr_json[src_address]["inboundInterface"],
857 )
858 )
859 return errormsg
860
861 logger.info(
862 "[DUT %s]: Verifying iif(Inbound Interface)"
863 " for (%s,%s) and joinState is %s [PASSED]!! "
864 " Found Expected: (%s)",
865 dut,
866 src_address,
867 grp_addr,
868 group_addr_json[src_address]["joinState"],
869 group_addr_json[src_address]["inboundInterface"],
870 )
871 if not found:
872 errormsg = (
873 "[DUT %s]: Verifying iif "
874 "(Inbound Interface) for (%s, %s) "
875 "[FAILED]!! "
876 " Expected: %s, Found: %s"
877 % (
878 dut,
879 src_address,
880 grp_addr,
881 in_interface,
882 group_addr_json[src_address]["inboundInterface"],
883 )
884 )
885 return errormsg
886
887 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
888 return True
889
890
891@retry(attempts=6, wait=2, return_is_str=True)
892def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses):
893 """
894 Verify join state is updated correctly and join timer is
895 running with the help of "show ip pim upstream" cli
896
897 Parameters
898 ----------
899 * `tgen`: topogen object
900 * `dut`: device under test
901 * `iif`: inbound interface
902 * `src_address`: source address
903 * `group_addresses`: IGMP group address
904
905 Usage
906 -----
907 dut = "r1"
908 iif = "r1-r0-eth0"
909 group_address = "225.1.1.1"
910 result = verify_join_state_and_timer(tgen, dut, iif, group_address)
911
912 Returns
913 -------
914 errormsg(str) or True
915 """
916
917 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
918 errormsg = ""
919
920 if dut not in tgen.routers():
921 return False
922
923 rnode = tgen.routers()[dut]
924
925 logger.info(
926 "[DUT: %s]: Verifying Join state and Join Timer" " for IGMP groups received:",
927 dut,
928 )
929 show_ip_pim_upstream_json = run_frr_cmd(
930 rnode, "show ip pim upstream json", isjson=True
931 )
932
933 if type(group_addresses) is not list:
934 group_addresses = [group_addresses]
935
936 for grp_addr in group_addresses:
937 # Verify group address
938 if grp_addr not in show_ip_pim_upstream_json:
939 errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
940 dut,
941 grp_addr,
942 )
943 return errormsg
944
945 group_addr_json = show_ip_pim_upstream_json[grp_addr]
946
947 # Verify source address
948 if src_address not in group_addr_json:
949 errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
950 dut,
951 src_address,
952 grp_addr,
953 )
954 return errormsg
955
956 # Verify join state
957 joinState = group_addr_json[src_address]["joinState"]
958 if joinState != "Joined":
959 error = (
960 "[DUT %s]: Verifying join state for"
961 " (%s,%s) [FAILED]!! "
962 " Expected: %s, Found: %s"
963 % (dut, src_address, grp_addr, "Joined", joinState)
964 )
965 errormsg = errormsg + "\n" + str(error)
966 else:
967 logger.info(
968 "[DUT %s]: Verifying join state for"
969 " (%s,%s) [PASSED]!! "
970 " Found Expected: %s",
971 dut,
972 src_address,
973 grp_addr,
974 joinState,
975 )
976
977 # Verify join timer
978 joinTimer = group_addr_json[src_address]["joinTimer"]
979 if not re.match(r"(\d{2}):(\d{2}):(\d{2})", joinTimer):
980 error = (
981 "[DUT %s]: Verifying join timer for"
982 " (%s,%s) [FAILED]!! "
983 " Expected: %s, Found: %s",
984 dut,
985 src_address,
986 grp_addr,
987 "join timer should be running",
988 joinTimer,
989 )
990 errormsg = errormsg + "\n" + str(error)
991 else:
992 logger.info(
993 "[DUT %s]: Verifying join timer is running"
994 " for (%s,%s) [PASSED]!! "
995 " Found Expected: %s",
996 dut,
997 src_address,
998 grp_addr,
999 joinTimer,
1000 )
1001
1002 if errormsg != "":
1003 return errormsg
1004
1005 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1006 return True
1007
1008
1009@retry(attempts=41, wait=2, return_is_dict=True)
1010def verify_ip_mroutes(
1011 tgen, dut, src_address, group_addresses, iif, oil, return_uptime=False, mwait=0
1012):
1013 """
1014 Verify ip mroutes and make sure (*, G)/(S, G) is present in mroutes
1015 by running "show ip pim upstream" cli
1016
1017 Parameters
1018 ----------
1019 * `tgen`: topogen object
1020 * `dut`: device under test
1021 * `src_address`: source address
1022 * `group_addresses`: IGMP group address
1023 * `iif`: Incoming interface
1024 * `oil`: Outgoing interface
1025 * `return_uptime`: If True, return uptime dict, default is False
1026 * `mwait`: Wait time, default is 0
1027
1028
1029 Usage
1030 -----
1031 dut = "r1"
1032 group_address = "225.1.1.1"
1033 result = verify_ip_mroutes(tgen, dut, src_address, group_address)
1034
1035 Returns
1036 -------
1037 errormsg(str) or True
1038 """
1039
1040 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1041
1042 if dut not in tgen.routers():
1043 return False
1044
1045 rnode = tgen.routers()[dut]
1046
1047 if return_uptime:
1048 logger.info("Sleeping for %s sec..", mwait)
1049 sleep(mwait)
1050
1051 logger.info("[DUT: %s]: Verifying ip mroutes", dut)
1052 show_ip_mroute_json = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
1053
1054 if return_uptime:
1055 uptime_dict = {}
1056
1057 if bool(show_ip_mroute_json) == False:
1058 error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
1059 return error_msg
1060
1061 if not isinstance(group_addresses, list):
1062 group_addresses = [group_addresses]
1063
1064 if not isinstance(iif, list) and iif is not "none":
1065 iif = [iif]
1066
1067 if not isinstance(oil, list) and oil is not "none":
1068 oil = [oil]
1069
1070 for grp_addr in group_addresses:
1071 if grp_addr not in show_ip_mroute_json:
1072 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
1073 dut,
1074 src_address,
1075 grp_addr,
1076 )
1077 return errormsg
1078 else:
1079 if return_uptime:
1080 uptime_dict[grp_addr] = {}
1081
1082 group_addr_json = show_ip_mroute_json[grp_addr]
1083
1084 if src_address not in group_addr_json:
1085 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
1086 dut,
1087 src_address,
1088 grp_addr,
1089 )
1090 return errormsg
1091 else:
1092 if return_uptime:
1093 uptime_dict[grp_addr][src_address] = {}
1094
1095 mroutes = group_addr_json[src_address]
1096
1097 if mroutes["installed"] != 0:
1098 logger.info(
1099 "[DUT %s]: mroute (%s,%s) is installed", dut, src_address, grp_addr
1100 )
1101
1102 if "oil" not in mroutes:
1103 if oil == "none" and mroutes["iif"] in iif:
1104 logger.info(
1105 "[DUT %s]: Verifying (%s, %s) mroute,"
1106 " [PASSED]!! Found Expected: "
1107 "(iif: %s, oil: %s, installed: (%s,%s))",
1108 dut,
1109 src_address,
1110 grp_addr,
1111 mroutes["iif"],
1112 oil,
1113 src_address,
1114 grp_addr,
1115 )
1116 else:
1117 errormsg = (
1118 "[DUT %s]: Verifying (%s, %s) mroute,"
1119 " [FAILED]!! "
1120 "Expected: (oil: %s, installed:"
1121 " (%s,%s)) Found: ( oil: none, "
1122 "installed: (%s,%s))"
1123 % (
1124 dut,
1125 src_address,
1126 grp_addr,
1127 oil,
1128 src_address,
1129 grp_addr,
1130 src_address,
1131 grp_addr,
1132 )
1133 )
1134
1135 return errormsg
1136
1137 else:
1138 found = False
1139 for route, data in mroutes["oil"].items():
1140 if route in oil and route != "pimreg":
1141 if (
1142 data["source"] == src_address
1143 and data["group"] == grp_addr
1144 and data["inboundInterface"] in iif
1145 and data["outboundInterface"] in oil
1146 ):
1147 if return_uptime:
1148
1149 uptime_dict[grp_addr][src_address] = data["upTime"]
1150
1151 logger.info(
1152 "[DUT %s]: Verifying (%s, %s)"
1153 " mroute, [PASSED]!! "
1154 "Found Expected: "
1155 "(iif: %s, oil: %s, installed:"
1156 " (%s,%s)",
1157 dut,
1158 src_address,
1159 grp_addr,
1160 data["inboundInterface"],
1161 data["outboundInterface"],
1162 data["source"],
1163 data["group"],
1164 )
1165 found = True
1166 break
1167 else:
1168 continue
1169
1170 if not found:
1171 errormsg = (
1172 "[DUT %s]: Verifying (%s, %s)"
1173 " mroute [FAILED]!! "
1174 "Expected in: (iif: %s, oil: %s,"
1175 " installed: (%s,%s)) Found: "
1176 "(iif: %s, oil: %s, "
1177 "installed: (%s,%s))"
1178 % (
1179 dut,
1180 src_address,
1181 grp_addr,
1182 iif,
1183 oil,
1184 src_address,
1185 grp_addr,
1186 data["inboundInterface"],
1187 data["outboundInterface"],
1188 data["source"],
1189 data["group"],
1190 )
1191 )
1192 return errormsg
1193
1194 else:
1195 errormsg = "[DUT %s]: mroute (%s,%s) is not installed" % (
1196 dut,
1197 src_address,
1198 grp_addr,
1199 )
1200 return errormsg
1201
1202 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1203 return True if return_uptime == False else uptime_dict
1204
1205
1206@retry(attempts=31, wait=2, return_is_str=True)
1207def verify_pim_rp_info(
1208 tgen, topo, dut, group_addresses, oif=None, rp=None, source=None, iamrp=None
1209):
1210 """
1211 Verify pim rp info by running "show ip pim rp-info" cli
1212
1213 Parameters
1214 ----------
1215 * `tgen`: topogen object
1216 * `topo`: JSON file handler
1217 * `dut`: device under test
1218 * `group_addresses`: IGMP group address
1219 * `oif`: outbound interface name
1220 * `rp`: RP address
1221 * `source`: Source of RP
1222 * `iamrp`: User defined RP
1223
1224 Usage
1225 -----
1226 dut = "r1"
1227 result = verify_pim_rp_info(tgen, topo, dut, group_address,
1228 rp=rp, source="BSR")
1229
1230 Returns
1231 -------
1232 errormsg(str) or True
1233 """
1234
1235 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1236
1237 if dut not in tgen.routers():
1238 return False
1239
1240 rnode = tgen.routers()[dut]
1241
1242 logger.info("[DUT: %s]: Verifying ip rp info", dut)
1243 show_ip_rp_info_json = run_frr_cmd(rnode, "show ip pim rp-info json", isjson=True)
1244
1245 if type(group_addresses) is not list:
1246 group_addresses = [group_addresses]
1247
1248 if type(oif) is not list:
1249 oif = [oif]
1250
1251 for grp_addr in group_addresses:
1252 if rp is None:
1253 rp_details = find_rp_details(tgen, topo)
1254
1255 if dut in rp_details:
1256 iamRP = True
1257 else:
1258 iamRP = False
1259 else:
1260 show_ip_route_json = run_frr_cmd(
1261 rnode, "show ip route connected json", isjson=True
1262 )
1263 for _rp in show_ip_route_json.keys():
1264 if rp == _rp.split("/")[0]:
1265 iamRP = True
1266 break
1267 else:
1268 iamRP = False
1269
1270 if rp not in show_ip_rp_info_json:
1271 errormsg = "[DUT %s]: Verifying rp-info" "for rp_address %s [FAILED]!! " % (
1272 dut,
1273 rp,
1274 )
1275 return errormsg
1276 else:
1277 group_addr_json = show_ip_rp_info_json[rp]
1278
1279 for rp_json in group_addr_json:
1280 if oif is not None:
1281 found = False
1282 if rp_json["outboundInterface"] not in oif:
1283 errormsg = (
1284 "[DUT %s]: Verifying OIF "
1285 "for group %s and RP %s [FAILED]!! "
1286 "Expected interfaces: (%s),"
1287 " Found: (%s)"
1288 % (dut, grp_addr, rp, oif, rp_json["outboundInterface"])
1289 )
1290 return errormsg
1291
1292 logger.info(
1293 "[DUT %s]: Verifying OIF "
1294 "for group %s and RP %s [PASSED]!! "
1295 "Found Expected: (%s)"
1296 % (dut, grp_addr, rp, rp_json["outboundInterface"])
1297 )
1298
1299 if source is not None:
1300 if rp_json["source"] != source:
1301 errormsg = (
1302 "[DUT %s]: Verifying SOURCE "
1303 "for group %s and RP %s [FAILED]!! "
1304 "Expected: (%s),"
1305 " Found: (%s)" % (dut, grp_addr, rp, source, rp_json["source"])
1306 )
1307 return errormsg
1308
1309 logger.info(
1310 "[DUT %s]: Verifying SOURCE "
1311 "for group %s and RP %s [PASSED]!! "
1312 "Found Expected: (%s)" % (dut, grp_addr, rp, rp_json["source"])
1313 )
1314
1315 if rp_json["group"] == grp_addr and iamrp is not None:
1316 if iamRP:
1317 if rp_json["iAmRP"]:
1318 logger.info(
1319 "[DUT %s]: Verifying group "
1320 "and iAmRP [PASSED]!!"
1321 " Found Expected: (%s, %s:%s)",
1322 dut,
1323 grp_addr,
1324 "iAmRP",
1325 rp_json["iAmRP"],
1326 )
1327 else:
1328 errormsg = (
1329 "[DUT %s]: Verifying group"
1330 "%s and iAmRP [FAILED]!! "
1331 "Expected: (iAmRP: %s),"
1332 " Found: (iAmRP: %s)"
1333 % (dut, grp_addr, "true", rp_json["iAmRP"])
1334 )
1335 return errormsg
1336
1337 if not iamRP:
1338 if rp_json["iAmRP"] == False:
1339 logger.info(
1340 "[DUT %s]: Verifying group "
1341 "and iAmNotRP [PASSED]!!"
1342 " Found Expected: (%s, %s:%s)",
1343 dut,
1344 grp_addr,
1345 "iAmRP",
1346 rp_json["iAmRP"],
1347 )
1348 else:
1349 errormsg = (
1350 "[DUT %s]: Verifying group"
1351 "%s and iAmRP [FAILED]!! "
1352 "Expected: (iAmRP: %s),"
1353 " Found: (iAmRP: %s)"
1354 % (dut, grp_addr, "false", rp_json["iAmRP"])
1355 )
1356 return errormsg
1357
1358 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1359 return True
1360
1361
1362@retry(attempts=31, wait=2, return_is_str=True)
1363def verify_pim_state(
1364 tgen, dut, iif, oil, group_addresses, src_address=None, installed_fl=None
1365):
1366 """
1367 Verify pim state by running "show ip pim state" cli
1368
1369 Parameters
1370 ----------
1371 * `tgen`: topogen object
1372 * `dut`: device under test
1373 * `iif`: inbound interface
1374 * `oil`: outbound interface
1375 * `group_addresses`: IGMP group address
1376 * `src_address`: source address, default = None
1377 * installed_fl` : Installed flag
1378
1379 Usage
1380 -----
1381 dut = "r1"
1382 iif = "r1-r3-eth1"
1383 oil = "r1-r0-eth0"
1384 group_address = "225.1.1.1"
1385 result = verify_pim_state(tgen, dut, iif, oil, group_address)
1386
1387 Returns
1388 -------
1389 errormsg(str) or True
1390 """
1391
1392 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1393
1394 if dut not in tgen.routers():
1395 return False
1396
1397 rnode = tgen.routers()[dut]
1398
1399 logger.info("[DUT: %s]: Verifying pim state", dut)
1400 show_pim_state_json = run_frr_cmd(rnode, "show ip pim state json", isjson=True)
1401
1402 if installed_fl is None:
1403 installed_fl = 1
1404
1405 if type(group_addresses) is not list:
1406 group_addresses = [group_addresses]
1407
1408 for grp_addr in group_addresses:
1409 if src_address is None:
1410 src_address = "*"
1411 pim_state_json = show_pim_state_json[grp_addr][src_address]
1412 else:
1413 pim_state_json = show_pim_state_json[grp_addr][src_address]
1414
1415 if pim_state_json["Installed"] == installed_fl:
1416 logger.info(
1417 "[DUT %s]: group %s is installed flag: %s",
1418 dut,
1419 grp_addr,
1420 pim_state_json["Installed"],
1421 )
1422 for interface, data in pim_state_json[iif].items():
1423 if interface != oil:
1424 continue
1425
1426 # Verify iif, oil and installed state
1427 if (
1428 data["group"] == grp_addr
1429 and data["installed"] == installed_fl
1430 and data["inboundInterface"] == iif
1431 and data["outboundInterface"] == oil
1432 ):
1433 logger.info(
1434 "[DUT %s]: Verifying pim state for group"
1435 " %s [PASSED]!! Found Expected: "
1436 "(iif: %s, oil: %s, installed: %s) ",
1437 dut,
1438 grp_addr,
1439 data["inboundInterface"],
1440 data["outboundInterface"],
1441 data["installed"],
1442 )
1443 else:
1444 errormsg = (
1445 "[DUT %s]: Verifying pim state for group"
1446 " %s, [FAILED]!! Expected: "
1447 "(iif: %s, oil: %s, installed: %s) ",
1448 "Found: (iif: %s, oil: %s, installed: %s)"
1449 % (
1450 dut,
1451 grp_addr,
1452 iif,
1453 oil,
1454 "1",
1455 data["inboundInterface"],
1456 data["outboundInterface"],
1457 data["installed"],
1458 ),
1459 )
1460 return errormsg
1461 else:
1462 errormsg = "[DUT %s]: %s install flag value not as expected" % (
1463 dut,
1464 grp_addr,
1465 )
1466 return errormsg
1467
1468 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1469 return True
1470
1471
1472def verify_pim_interface_traffic(tgen, input_dict):
1473 """
1474 Verify ip pim interface traffice by running
1475 "show ip pim interface traffic" cli
1476
1477 Parameters
1478 ----------
1479 * `tgen`: topogen object
1480 * `input_dict(dict)`: defines DUT, what and from which interfaces
1481 traffic needs to be verified
1482 Usage
1483 -----
1484 input_dict = {
1485 "r1": {
1486 "r1-r0-eth0": {
1487 "helloRx": 0,
1488 "helloTx": 1,
1489 "joinRx": 0,
1490 "joinTx": 0
1491 }
1492 }
1493 }
1494
1495 result = verify_pim_interface_traffic(tgen, input_dict)
1496
1497 Returns
1498 -------
1499 errormsg(str) or True
1500 """
1501
1502 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1503
1504 output_dict = {}
1505 for dut in input_dict.keys():
1506 if dut not in tgen.routers():
1507 continue
1508
1509 rnode = tgen.routers()[dut]
1510
1511 logger.info("[DUT: %s]: Verifying pim interface traffic", dut)
1512 show_pim_intf_traffic_json = run_frr_cmd(
1513 rnode, "show ip pim interface traffic json", isjson=True
1514 )
1515
1516 output_dict[dut] = {}
1517 for intf, data in input_dict[dut].items():
1518 interface_json = show_pim_intf_traffic_json[intf]
1519 for state in data:
1520
1521 # Verify Tx/Rx
1522 if state in interface_json:
1523 output_dict[dut][state] = interface_json[state]
1524 else:
1525 errormsg = (
1526 "[DUT %s]: %s is not present"
1527 "for interface %s [FAILED]!! " % (dut, state, intf)
1528 )
1529 return errormsg
1530
1531 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1532 return output_dict
1533
1534
eab72dc8 1535@retry(attempts=21, wait=2, return_is_str=True)
1536def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None):
e8cd26fd 1537 """
1538 Verify all PIM interface are up and running, config is verified
1539 using "show ip pim interface" cli
1540
1541 Parameters
1542 ----------
1543 * `tgen`: topogen object
1544 * `topo` : json file data
1545 * `dut` : device under test
eab72dc8 1546 * `interface` : interface name
1547 * `interface_ip` : interface ip address
e8cd26fd 1548
1549 Usage
1550 -----
eab72dc8 1551 result = verify_pim_interfacetgen, topo, dut, interface=ens192, interface_ip=20.1.1.1)
e8cd26fd 1552
1553 Returns
1554 -------
1555 errormsg(str) or True
1556 """
1557
1558 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1559
1560 for router in tgen.routers():
1561 if router != dut:
1562 continue
1563
1564 logger.info("[DUT: %s]: Verifying PIM interface status:", dut)
1565
1566 rnode = tgen.routers()[dut]
eab72dc8 1567 show_ip_pim_interface_json = rnode.\
1568 vtysh_cmd("show ip pim interface json", isjson=True)
1569
1570 logger.info("show_ip_pim_interface_json: \n %s",
1571 show_ip_pim_interface_json)
1572
1573 if interface_ip:
1574 if interface in show_ip_pim_interface_json:
1575 pim_intf_json = show_ip_pim_interface_json[interface]
1576 if pim_intf_json["address"] != interface_ip:
1577 errormsg = ("[DUT %s]: PIM interface "
1578 "ip is not correct "
1579 "[FAILED]!! Expected : %s, Found : %s"
1580 %(dut, pim_intf_json["address"],interface_ip))
1581 return errormsg
1582 else:
1583 logger.info("[DUT %s]: PIM interface "
1584 "ip is correct "
1585 "[Passed]!! Expected : %s, Found : %s"
1586 %(dut, pim_intf_json["address"],interface_ip))
1587 return True
1588 else:
1589 for destLink, data in topo["routers"][dut]["links"].items():
1590 if "type" in data and data["type"] == "loopback":
1591 continue
e8cd26fd 1592
eab72dc8 1593 if "pim" in data and data["pim"] == "enable":
1594 pim_interface = data["interface"]
1595 pim_intf_ip = data["ipv4"].split("/")[0]
e8cd26fd 1596
eab72dc8 1597 if pim_interface in show_ip_pim_interface_json:
1598 pim_intf_json = show_ip_pim_interface_json\
1599 [pim_interface]
e8cd26fd 1600
1601 # Verifying PIM interface
eab72dc8 1602 if pim_intf_json["address"] != pim_intf_ip and \
1603 pim_intf_json["state"] != "up":
1604 errormsg = ("[DUT %s]: PIM interface: %s "
1605 "PIM interface ip: %s, status check "
1606 "[FAILED]!! Expected : %s, Found : %s"
1607 %(dut, pim_interface, pim_intf_ip,
1608 pim_interface, pim_intf_json["state"]))
e8cd26fd 1609 return errormsg
1610
eab72dc8 1611 logger.info("[DUT %s]: PIM interface: %s, "
1612 "interface ip: %s, status: %s"
1613 " [PASSED]!!",
1614 dut, pim_interface, pim_intf_ip,
1615 pim_intf_json["state"])
e8cd26fd 1616
1617 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1618 return True
1619
1620
1621def clear_ip_pim_interface_traffic(tgen, topo):
1622 """
1623 Clear ip pim interface traffice by running
1624 "clear ip pim interface traffic" cli
1625
1626 Parameters
1627 ----------
1628 * `tgen`: topogen object
1629 Usage
1630 -----
1631
1632 result = clear_ip_pim_interface_traffic(tgen, topo)
1633
1634 Returns
1635 -------
1636 errormsg(str) or True
1637 """
1638
1639 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1640
1641 for dut in tgen.routers():
1642 if "pim" not in topo["routers"][dut]:
1643 continue
1644
1645 rnode = tgen.routers()[dut]
1646
1647 logger.info("[DUT: %s]: Clearing pim interface traffic", dut)
1648 result = run_frr_cmd(rnode, "clear ip pim interface traffic")
1649
1650 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1651
1652 return True
1653
1654
1655def clear_ip_pim_interfaces(tgen, dut):
1656 """
1657 Clear ip pim interface by running
1658 "clear ip pim interfaces" cli
1659
1660 Parameters
1661 ----------
1662 * `tgen`: topogen object
1663 * `dut`: Device Under Test
1664 Usage
1665 -----
1666
1667 result = clear_ip_pim_interfaces(tgen, dut)
1668
1669 Returns
1670 -------
1671 errormsg(str) or True
1672 """
1673
1674 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1675
1676 nh_before_clear = {}
1677 nh_after_clear = {}
1678
1679 rnode = tgen.routers()[dut]
1680
1681 logger.info("[DUT: %s]: Verify pim neighbor before pim" " neighbor clear", dut)
1682 # To add uptime initially
1683 sleep(10)
1684 run_json_before = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
1685
1686 for key, value in run_json_before.items():
1687 if bool(value):
1688 for _key, _value in value.items():
1689 nh_before_clear[key] = _value["upTime"]
1690
1691 # Clearing PIM neighbors
1692 logger.info("[DUT: %s]: Clearing pim interfaces", dut)
1693 run_frr_cmd(rnode, "clear ip pim interfaces")
1694
1695 logger.info("[DUT: %s]: Verify pim neighbor after pim" " neighbor clear", dut)
1696
1697 found = False
1698
1699 # Waiting for maximum 60 sec
1700 fail_intf = []
1701 for retry in range(1, 13):
1702 logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut)
1703 sleep(5)
1704 run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
1705 found = True
1706 for pim_intf in nh_before_clear.keys():
1707 if pim_intf not in run_json_after or not run_json_after[pim_intf]:
1708 found = False
1709 fail_intf.append(pim_intf)
1710
1711 if found is True:
1712 break
1713 else:
1714 errormsg = (
1715 "[DUT: %s]: pim neighborship is not formed for %s"
1716 "after clear_ip_pim_interfaces %s [FAILED!!]",
1717 dut,
1718 fail_intf,
1719 )
1720 return errormsg
1721
1722 for key, value in run_json_after.items():
1723 if bool(value):
1724 for _key, _value in value.items():
1725 nh_after_clear[key] = _value["upTime"]
1726
1727 # Verify uptime for neighbors
1728 for pim_intf in nh_before_clear.keys():
1729 d1 = datetime.datetime.strptime(nh_before_clear[pim_intf], "%H:%M:%S")
1730 d2 = datetime.datetime.strptime(nh_after_clear[pim_intf], "%H:%M:%S")
1731 if d2 >= d1:
1732 errormsg = (
1733 "[DUT: %s]: PIM neighborship is not cleared for",
1734 " interface %s [FAILED!!]",
1735 dut,
1736 pim_intf,
1737 )
1738
1739 logger.info("[DUT: %s]: PIM neighborship is cleared [PASSED!!]")
1740
1741 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1742
1743 return True
1744
1745
1746def clear_ip_igmp_interfaces(tgen, dut):
1747 """
1748 Clear ip igmp interfaces by running
1749 "clear ip igmp interfaces" cli
1750
1751 Parameters
1752 ----------
1753 * `tgen`: topogen object
1754 * `dut`: device under test
1755
1756 Usage
1757 -----
1758 dut = "r1"
1759 result = clear_ip_igmp_interfaces(tgen, dut)
1760 Returns
1761 -------
1762 errormsg(str) or True
1763 """
1764
1765 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1766
1767 group_before_clear = {}
1768 group_after_clear = {}
1769
1770 rnode = tgen.routers()[dut]
1771
1772 logger.info("[DUT: %s]: IGMP group uptime before clear" " igmp groups:", dut)
1773 igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
1774
1775 total_groups_before_clear = igmp_json["totalGroups"]
1776
1777 for key, value in igmp_json.items():
1778 if type(value) is not dict:
1779 continue
1780
1781 groups = value["groups"]
1782 group = groups[0]["group"]
1783 uptime = groups[0]["uptime"]
1784 group_before_clear[group] = uptime
1785
1786 logger.info("[DUT: %s]: Clearing ip igmp interfaces", dut)
1787 result = run_frr_cmd(rnode, "clear ip igmp interfaces")
1788
1789 # Waiting for maximum 60 sec
1790 for retry in range(1, 13):
1791 logger.info(
1792 "[DUT: %s]: Waiting for 5 sec for igmp interfaces" " to come up", dut
1793 )
1794 sleep(5)
1795 igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
1796
1797 total_groups_after_clear = igmp_json["totalGroups"]
1798
1799 if total_groups_before_clear == total_groups_after_clear:
1800 break
1801
1802 for key, value in igmp_json.items():
1803 if type(value) is not dict:
1804 continue
1805
1806 groups = value["groups"]
1807 group = groups[0]["group"]
1808 uptime = groups[0]["uptime"]
1809 group_after_clear[group] = uptime
1810
1811 # Verify uptime for groups
1812 for group in group_before_clear.keys():
1813 d1 = datetime.datetime.strptime(group_before_clear[group], "%H:%M:%S")
1814 d2 = datetime.datetime.strptime(group_after_clear[group], "%H:%M:%S")
1815 if d2 >= d1:
1816 errormsg = ("[DUT: %s]: IGMP group is not cleared", " [FAILED!!]", dut)
1817
1818 logger.info("[DUT: %s]: IGMP group is cleared [PASSED!!]")
1819
1820 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1821
1822 return True
1823
1824
1825@retry(attempts=10, wait=2, return_is_str=True)
1826def clear_ip_mroute_verify(tgen, dut):
1827 """
1828 Clear ip mroute by running "clear ip mroute" cli and verify
1829 mroutes are up again after mroute clear
1830
1831 Parameters
1832 ----------
1833 * `tgen`: topogen object
1834 * `dut`: Device Under Test
1835 Usage
1836 -----
1837
1838 result = clear_ip_mroute_verify(tgen, dut)
1839
1840 Returns
1841 -------
1842 errormsg(str) or True
1843 """
1844
1845 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1846
1847 mroute_before_clear = {}
1848 mroute_after_clear = {}
1849
1850 rnode = tgen.routers()[dut]
1851
e8cd26fd 1852 logger.info("[DUT: %s]: IP mroutes uptime before clear", dut)
1853 mroute_json_1 = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
1854
1855 for group in mroute_json_1.keys():
1856 mroute_before_clear[group] = {}
1857 for key in mroute_json_1[group].keys():
1858 for _key, _value in mroute_json_1[group][key]["oil"].items():
1859 if _key != "pimreg":
1860 mroute_before_clear[group][key] = _value["upTime"]
1861
1862 logger.info("[DUT: %s]: Clearing ip mroute", dut)
1863 result = run_frr_cmd(rnode, "clear ip mroute")
1864
1865 # RFC 3376: 8.2. Query Interval - Default: 125 seconds
1866 # So waiting for maximum 130 sec to get the igmp report
1867 for retry in range(1, 26):
1868 logger.info("[DUT: %s]: Waiting for 2 sec for mroutes" " to come up", dut)
1869 sleep(5)
1870 keys_json1 = mroute_json_1.keys()
1871 mroute_json_2 = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
1872
1873 if bool(mroute_json_2):
1874 keys_json2 = mroute_json_2.keys()
1875
1876 for group in mroute_json_2.keys():
1877 flag = False
1878 for key in mroute_json_2[group].keys():
1879 if "oil" not in mroute_json_2[group]:
1880 continue
1881
1882 for _key, _value in mroute_json_2[group][key]["oil"].items():
1883 if _key != "pimreg" and keys_json1 == keys_json2:
1884 break
1885 flag = True
1886 if flag:
1887 break
1888 else:
1889 continue
1890
1891 for group in mroute_json_2.keys():
1892 mroute_after_clear[group] = {}
1893 for key in mroute_json_2[group].keys():
1894 for _key, _value in mroute_json_2[group][key]["oil"].items():
1895 if _key != "pimreg":
1896 mroute_after_clear[group][key] = _value["upTime"]
1897
1898 # Verify uptime for mroute
1899 for group in mroute_before_clear.keys():
1900 for source in mroute_before_clear[group].keys():
1901 if set(mroute_before_clear[group]) != set(mroute_after_clear[group]):
1902 errormsg = (
1903 "[DUT: %s]: mroute (%s, %s) has not come"
1904 " up after mroute clear [FAILED!!]" % (dut, source, group)
1905 )
1906 return errormsg
1907
1908 d1 = datetime.datetime.strptime(
1909 mroute_before_clear[group][source], "%H:%M:%S"
1910 )
1911 d2 = datetime.datetime.strptime(
1912 mroute_after_clear[group][source], "%H:%M:%S"
1913 )
1914 if d2 >= d1:
1915 errormsg = "[DUT: %s]: IP mroute is not cleared" " [FAILED!!]" % (dut)
1916
1917 logger.info("[DUT: %s]: IP mroute is cleared [PASSED!!]", dut)
1918
1919 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1920
1921 return True
1922
1923
1924def clear_ip_mroute(tgen, dut=None):
1925 """
1926 Clear ip mroute by running "clear ip mroute" cli
1927
1928 Parameters
1929 ----------
1930 * `tgen`: topogen object
1931 * `dut`: device under test, default None
1932
1933 Usage
1934 -----
1935 clear_ip_mroute(tgen, dut)
1936 """
1937
1938 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1939
1940 router_list = tgen.routers()
1941 for router, rnode in router_list.items():
1942 if dut is not None and router != dut:
1943 continue
1944
1945 logger.debug("[DUT: %s]: Clearing ip mroute", router)
1946 rnode.vtysh_cmd("clear ip mroute")
1947
1948 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1949
1950
1951def reconfig_interfaces(tgen, topo, senderRouter, receiverRouter, packet=None):
1952 """
1953 Configure interface ip for sender and receiver routers
1954 as per bsr packet
1955
1956 Parameters
1957 ----------
1958 * `tgen` : Topogen object
1959 * `topo` : json file data
1960 * `senderRouter` : Sender router
1961 * `receiverRouter` : Receiver router
1962 * `packet` : BSR packet in raw format
1963
1964 Returns
1965 -------
1966 True or False
1967 """
1968 result = False
1969 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1970
1971 try:
1972 config_data = []
1973
1974 src_ip = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["src_ip"]
1975 dest_ip = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["dest_ip"]
1976
1977 for destLink, data in topo["routers"][senderRouter]["links"].items():
1978 if "type" in data and data["type"] == "loopback":
1979 continue
1980
1981 if "pim" in data and data["pim"] == "enable":
1982 sender_interface = data["interface"]
1983 sender_interface_ip = data["ipv4"]
1984
1985 config_data.append("interface {}".format(sender_interface))
1986 config_data.append("no ip address {}".format(sender_interface_ip))
1987 config_data.append("ip address {}".format(src_ip))
1988
1989 result = create_common_configuration(
1990 tgen, senderRouter, config_data, "interface_config"
1991 )
1992 if result is not True:
1993 return False
1994
1995 config_data = []
1996 links = topo["routers"][destLink]["links"]
1997 pim_neighbor = {key: links[key] for key in [senderRouter]}
1998
1999 data = pim_neighbor[senderRouter]
2000 if "type" in data and data["type"] == "loopback":
2001 continue
2002
2003 if "pim" in data and data["pim"] == "enable":
2004 receiver_interface = data["interface"]
2005 receiver_interface_ip = data["ipv4"]
2006
2007 config_data.append("interface {}".format(receiver_interface))
2008 config_data.append("no ip address {}".format(receiver_interface_ip))
2009 config_data.append("ip address {}".format(dest_ip))
2010
2011 result = create_common_configuration(
2012 tgen, receiverRouter, config_data, "interface_config"
2013 )
2014 if result is not True:
2015 return False
2016
2017 except InvalidCLIError:
2018 # Traceback
2019 errormsg = traceback.format_exc()
2020 logger.error(errormsg)
2021 return errormsg
2022
2023 logger.debug("Exiting lib API: reconfig_interfaces()")
2024 return result
2025
2026
2027def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping):
2028 """
2029 Add physical interfaces tp RP for all the RPs
2030
2031 Parameters
2032 ----------
2033 * `tgen` : Topogen object
2034 * `topo` : json file data
2035 * `interface` : RP interface
2036 * `rp` : rp for given topology
2037 * `rp_mapping` : dictionary of all groups and RPs
2038
2039 Returns
2040 -------
2041 True or False
2042 """
2043 result = False
2044 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2045
2046 try:
2047 config_data = []
2048
2049 for group, rp_list in rp_mapping.items():
2050 for _rp in rp_list:
2051 config_data.append("interface {}".format(interface))
2052 config_data.append("ip address {}".format(_rp))
2053 config_data.append("ip pim")
2054
2055 result = create_common_configuration(
2056 tgen, rp, config_data, "interface_config"
2057 )
2058 if result is not True:
2059 return False
2060
2061 except InvalidCLIError:
2062 # Traceback
2063 errormsg = traceback.format_exc()
2064 logger.error(errormsg)
2065 return errormsg
2066
2067 logger.debug("Exiting lib API: add_rp_interfaces_and_pim_config()")
2068 return result
2069
2070
2071def scapy_send_bsr_raw_packet(
2072 tgen, topo, senderRouter, receiverRouter, packet=None, interval=1, count=1
2073):
2074 """
2075 Using scapy Raw() method to send BSR raw packet from one FRR
2076 to other
2077
2078 Parameters:
2079 -----------
2080 * `tgen` : Topogen object
2081 * `topo` : json file data
2082 * `senderRouter` : Sender router
2083 * `receiverRouter` : Receiver router
2084 * `packet` : BSR packet in raw format
2085 * `interval` : Interval between the packets
2086 * `count` : Number of packets to be sent
2087
2088 returns:
2089 --------
2090 errormsg or True
2091 """
2092
2093 global CWD
2094 result = ""
2095 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2096
2097 rnode = tgen.routers()[senderRouter]
2098
2099 for destLink, data in topo["routers"][senderRouter]["links"].items():
2100 if "type" in data and data["type"] == "loopback":
2101 continue
2102
2103 if "pim" in data and data["pim"] == "enable":
2104 sender_interface = data["interface"]
2105
2106 packet = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["data"]
2107
2108 if interval > 1 or count > 1:
2109 cmd = (
2110 "nohup /usr/bin/python {}/send_bsr_packet.py '{}' '{}' "
2111 "--interval={} --count={} &".format(
2112 CWD, packet, sender_interface, interval, count
2113 )
2114 )
2115 else:
2116 cmd = (
2117 "/usr/bin/python {}/send_bsr_packet.py '{}' '{}' "
2118 "--interval={} --count={}".format(
2119 CWD, packet, sender_interface, interval, count
2120 )
2121 )
2122
2123 logger.info("Scapy cmd: \n %s", cmd)
2124 result = rnode.run(cmd)
2125
2126 if result == "":
2127 return result
2128
2129 logger.debug("Exiting lib API: scapy_send_bsr_raw_packet")
2130 return True
2131
2132
2133def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None):
2134 """
2135 Find which RP is having lowest prioriy and returns rp IP
2136
2137 Parameters
2138 ----------
2139 * `tgen`: topogen object
2140 * `dut`: device under test
2141 * `bsr`: BSR address
2142 * 'grp': Group Address
2143
2144 Usage
2145 -----
2146 dut = "r1"
2147 result = verify_pim_rp_info(tgen, dut, bsr)
2148
2149 Returns:
2150 dictionary: group and RP, which has to be installed as per
2151 lowest priority or highest priority
2152 """
2153
2154 rp_details = {}
2155 rnode = tgen.routers()[dut]
2156
2157 logger.info("[DUT: %s]: Fetching rp details from bsrp-info", dut)
2158 bsrp_json = run_frr_cmd(rnode, "show ip pim bsrp-info json", isjson=True)
2159
2160 if grp not in bsrp_json:
2161 return {}
2162
2163 for group, rp_data in bsrp_json.items():
2164 if group == "BSR Address" and bsrp_json["BSR Address"] == bsr:
2165 continue
2166
2167 if group != grp:
2168 continue
2169
2170 rp_priority = {}
2171 rp_hash = {}
2172
2173 for rp, value in rp_data.items():
2174 if rp == "Pending RP count":
2175 continue
2176 rp_priority[value["Rp Address"]] = value["Rp Priority"]
2177 rp_hash[value["Rp Address"]] = value["Hash Val"]
2178
2179 priority_dict = dict(zip(rp_priority.values(), rp_priority.keys()))
2180 hash_dict = dict(zip(rp_hash.values(), rp_hash.keys()))
2181
2182 # RP with lowest priority
2183 if len(priority_dict) != 1:
2184 rp_p, lowest_priority = sorted(rp_priority.items(), key=lambda x: x[1])[0]
2185 rp_details[group] = rp_p
2186
2187 # RP with highest hash value
2188 if len(priority_dict) == 1:
2189 rp_h, highest_hash = sorted(rp_hash.items(), key=lambda x: x[1])[-1]
2190 rp_details[group] = rp_h
2191
2192 # RP with highest IP address
2193 if len(priority_dict) == 1 and len(hash_dict) == 1:
2194 rp_details[group] = sorted(rp_priority.keys())[-1]
2195
2196 return rp_details
2197
2198
2199@retry(attempts=6, wait=2, return_is_str=True)
2200def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None):
2201 """
2202 Verify pim rp info by running "show ip pim rp-info" cli
2203
2204 Parameters
2205 ----------
2206 * `tgen`: topogen object
2207 * `topo`: JSON file handler
2208 * `dut`: device under test
2209 * `grp_addr`: IGMP group address
2210 * 'rp_source': source from which rp installed
2211 * 'rpadd': rp address
2212
2213 Usage
2214 -----
2215 dut = "r1"
2216 group_address = "225.1.1.1"
2217 rp_source = "BSR"
2218 result = verify_pim_rp_and_source(tgen, topo, dut, group_address, rp_source)
2219
2220 Returns
2221 -------
2222 errormsg(str) or True
2223 """
2224
2225 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2226
2227 if dut not in tgen.routers():
2228 return False
2229
2230 rnode = tgen.routers()[dut]
2231
2232 logger.info("[DUT: %s]: Verifying ip rp info", dut)
2233 show_ip_rp_info_json = run_frr_cmd(rnode, "show ip pim rp-info json", isjson=True)
2234
2235 if rpadd != None:
2236 rp_json = show_ip_rp_info_json[rpadd]
2237 if rp_json[0]["group"] == grp_addr:
2238 if rp_json[0]["source"] == rp_source:
2239 logger.info(
2240 "[DUT %s]: Verifying Group and rp_source [PASSED]"
2241 "Found Expected: %s, %s"
2242 % (dut, rp_json[0]["group"], rp_json[0]["source"])
2243 )
2244 return True
2245 else:
2246 errormsg = (
2247 "[DUT %s]: Verifying Group and rp_source [FAILED]"
2248 "Expected (%s, %s) "
2249 "Found (%s, %s)"
2250 % (
2251 dut,
2252 grp_addr,
2253 rp_source,
2254 rp_json[0]["group"],
2255 rp_json[0]["source"],
2256 )
2257 )
2258 return errormsg
2259 errormsg = (
2260 "[DUT %s]: Verifying Group and rp_source [FAILED]"
2261 "Expected: %s, %s but not found" % (dut, grp_addr, rp_source)
2262 )
2263 return errormsg
2264
2265 for rp in show_ip_rp_info_json:
2266 rp_json = show_ip_rp_info_json[rp]
2267 logger.info("%s", rp_json)
2268 if rp_json[0]["group"] == grp_addr:
2269 if rp_json[0]["source"] == rp_source:
2270 logger.info(
2271 "[DUT %s]: Verifying Group and rp_source [PASSED]"
2272 "Found Expected: %s, %s"
2273 % (dut, rp_json[0]["group"], rp_json[0]["source"])
2274 )
2275 return True
2276 else:
2277 errormsg = (
2278 "[DUT %s]: Verifying Group and rp_source [FAILED]"
2279 "Expected (%s, %s) "
2280 "Found (%s, %s)"
2281 % (
2282 dut,
2283 grp_addr,
2284 rp_source,
2285 rp_json[0]["group"],
2286 rp_json[0]["source"],
2287 )
2288 )
2289 return errormsg
2290
2291 errormsg = (
2292 "[DUT %s]: Verifying Group and rp_source [FAILED]"
2293 "Expected: %s, %s but not found" % (dut, grp_addr, rp_source)
2294 )
2295
2296 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2297
2298 return errormsg
2299
2300
2301@retry(attempts=31, wait=2, return_is_str=True)
2302def verify_pim_bsr(tgen, topo, dut, bsr_ip):
2303 """
2304 Verify all PIM interface are up and running, config is verified
2305 using "show ip pim interface" cli
2306
2307 Parameters
2308 ----------
2309 * `tgen`: topogen object
2310 * `topo` : json file data
2311 * `dut` : device under test
2312 * 'bsr' : bsr ip to be verified
2313
2314 Usage
2315 -----
2316 result = verify_pim_bsr(tgen, topo, dut, bsr_ip)
2317
2318 Returns
2319 -------
2320 errormsg(str) or True
2321 """
2322
2323 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2324
2325 for router in tgen.routers():
2326 if router != dut:
2327 continue
2328
2329 logger.info("[DUT: %s]: Verifying PIM bsr status:", dut)
2330
2331 rnode = tgen.routers()[dut]
2332 pim_bsr_json = rnode.vtysh_cmd("show ip pim bsr json", isjson=True)
2333
2334 logger.info("show_ip_pim_bsr_json: \n %s", pim_bsr_json)
2335
2336 # Verifying PIM bsr
2337 if pim_bsr_json["bsr"] != bsr_ip:
2338 errormsg = (
2339 "[DUT %s]:"
2340 "bsr status: not found"
2341 "[FAILED]!! Expected : %s, Found : %s"
2342 % (dut, bsr_ip, pim_bsr_json["bsr"])
2343 )
2344 return errormsg
2345
2346 logger.info(
2347 "[DUT %s]:" " bsr status: found, Address :%s" " [PASSED]!!",
2348 dut,
2349 pim_bsr_json["bsr"],
2350 )
2351
2352 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2353 return True
2354
2355
2356@retry(attempts=31, wait=2, return_is_str=True)
2357def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=None):
2358 """
2359 Verify IP PIM upstream rpf, config is verified
2360 using "show ip pim neighbor" cli
2361
2362 Parameters
2363 ----------
2364 * `tgen`: topogen object
2365 * `topo` : json file data
2366 * `dut` : devuce under test
2367 * `interface` : upstream interface
2368 * `group_addresses` : list of group address for which upstream info
2369 needs to be checked
2370 * `rp` : RP address
2371
2372 Usage
2373 -----
2374 result = verify_ip_pim_upstream_rpf(gen, topo, dut, interface,
2375 group_addresses, rp=None)
2376
2377 Returns
2378 -------
2379 errormsg(str) or True
2380 """
2381
2382 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2383
2384 if "pim" in topo["routers"][dut]:
2385
2386 logger.info("[DUT: %s]: Verifying ip pim upstream rpf:", dut)
2387
2388 rnode = tgen.routers()[dut]
2389 show_ip_pim_upstream_rpf_json = rnode.vtysh_cmd(
2390 "show ip pim upstream-rpf json", isjson=True
2391 )
2392
2393 logger.info(
2394 "show_ip_pim_upstream_rpf_json: \n %s", show_ip_pim_upstream_rpf_json
2395 )
2396
2397 if type(group_addresses) is not list:
2398 group_addresses = [group_addresses]
2399
2400 for grp_addr in group_addresses:
2401 for destLink, data in topo["routers"][dut]["links"].items():
2402 if "type" in data and data["type"] == "loopback":
2403 continue
2404
2405 if "pim" not in topo["routers"][destLink]:
2406 continue
2407
2408 # Verify RP info
2409 if rp is None:
2410 rp_details = find_rp_details(tgen, topo)
2411 else:
2412 rp_details = {dut: ip}
2413 rp_details[dut] = rp
2414
2415 if dut in rp_details:
2416 pim_nh_intf_ip = topo["routers"][dut]["links"]["lo"]["ipv4"].split(
2417 "/"
2418 )[0]
2419 else:
2420 if destLink not in interface:
2421 continue
2422
2423 links = topo["routers"][destLink]["links"]
2424 pim_neighbor = {key: links[key] for key in [dut]}
2425
2426 data = pim_neighbor[dut]
2427 if "pim" in data and data["pim"] == "enable":
2428 pim_nh_intf_ip = data["ipv4"].split("/")[0]
2429
2430 upstream_rpf_json = show_ip_pim_upstream_rpf_json[grp_addr]["*"]
2431
2432 # Verifying ip pim upstream rpf
2433 if (
2434 upstream_rpf_json["rpfInterface"] == interface
2435 and upstream_rpf_json["ribNexthop"] != pim_nh_intf_ip
2436 ):
2437 errormsg = (
2438 "[DUT %s]: Verifying group: %s, "
2439 "rpf interface: %s, "
2440 " rib Nexthop check [FAILED]!!"
2441 "Expected: %s, Found: %s"
2442 % (
2443 dut,
2444 grp_addr,
2445 interface,
2446 pim_nh_intf_ip,
2447 upstream_rpf_json["ribNexthop"],
2448 )
2449 )
2450 return errormsg
2451
2452 logger.info(
2453 "[DUT %s]: Verifying group: %s,"
2454 " rpf interface: %s, "
2455 " rib Nexthop: %s [PASSED]!!",
2456 dut,
2457 grp_addr,
2458 interface,
2459 pim_nh_intf_ip,
2460 )
2461
2462 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2463 return True
2464
2465
2466def enable_disable_pim_unicast_bsm(tgen, router, intf, enable=True):
2467 """
2468 Helper API to enable or disable pim bsm on interfaces
2469
2470 Parameters
2471 ----------
2472 * `tgen` : Topogen object
2473 * `router` : router id to be configured.
2474 * `intf` : Interface to be configured
2475 * `enable` : this flag denotes if config should be enabled or disabled
2476
2477 Returns
2478 -------
2479 True or False
2480 """
2481 result = False
2482 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2483
2484 try:
2485 config_data = []
2486 cmd = "interface {}".format(intf)
2487 config_data.append(cmd)
2488
2489 if enable == True:
2490 config_data.append("ip pim unicast-bsm")
2491 else:
2492 config_data.append("no ip pim unicast-bsm")
2493
2494 result = create_common_configuration(
2495 tgen, router, config_data, "interface_config", build=False
2496 )
2497 if result is not True:
2498 return False
2499
2500 except InvalidCLIError:
2501 # Traceback
2502 errormsg = traceback.format_exc()
2503 logger.error(errormsg)
2504 return errormsg
2505
2506 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2507 return result
2508
2509
2510def enable_disable_pim_bsm(tgen, router, intf, enable=True):
2511 """
2512 Helper API to enable or disable pim bsm on interfaces
2513
2514 Parameters
2515 ----------
2516 * `tgen` : Topogen object
2517 * `router` : router id to be configured.
2518 * `intf` : Interface to be configured
2519 * `enable` : this flag denotes if config should be enabled or disabled
2520
2521 Returns
2522 -------
2523 True or False
2524 """
2525 result = False
2526 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2527
2528 try:
2529 config_data = []
2530 cmd = "interface {}".format(intf)
2531 config_data.append(cmd)
2532
2533 if enable is True:
2534 config_data.append("ip pim bsm")
2535 else:
2536 config_data.append("no ip pim bsm")
2537
2538 result = create_common_configuration(
2539 tgen, router, config_data, "interface_config", build=False
2540 )
2541 if result is not True:
2542 return False
2543
2544 except InvalidCLIError:
2545 # Traceback
2546 errormsg = traceback.format_exc()
2547 logger.error(errormsg)
2548 return errormsg
2549
2550 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2551 return result
2552
2553
2554@retry(attempts=31, wait=2, return_is_str=True)
2555def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=None):
2556 """
2557 Verify ip pim join by running "show ip pim join" cli
2558
2559 Parameters
2560 ----------
2561 * `tgen`: topogen object
2562 * `topo`: JSON file handler
2563 * `dut`: device under test
2564 * `interface`: interface name, from which PIM join would come
2565 * `group_addresses`: IGMP group address
2566 * `src_address`: Source address
2567
2568 Usage
2569 -----
2570 dut = "r1"
2571 interface = "r1-r0-eth0"
2572 group_address = "225.1.1.1"
2573 result = verify_ip_pim_join(tgen, dut, star, group_address, interface)
2574
2575 Returns
2576 -------
2577 errormsg(str) or True
2578 """
2579 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2580
2581 if dut not in tgen.routers():
2582 return False
2583
2584 rnode = tgen.routers()[dut]
2585
2586 logger.info("[DUT: %s]: Verifying pim join", dut)
2587 show_pim_join_json = run_frr_cmd(rnode, "show ip pim join json", isjson=True)
2588
2589 if type(group_addresses) is not list:
2590 group_addresses = [group_addresses]
2591
2592 for grp_addr in group_addresses:
2593 # Verify if IGMP is enabled in DUT
2594 if "igmp" not in topo["routers"][dut]:
2595 pim_join = True
2596 else:
2597 pim_join = False
2598
2599 interface_json = show_pim_join_json[interface]
2600
2601 grp_addr = grp_addr.split("/")[0]
2602 for source, data in interface_json[grp_addr].items():
2603
2604 # Verify pim join
2605 if pim_join:
2606 if data["group"] == grp_addr and data["channelJoinName"] == "JOIN":
2607 logger.info(
2608 "[DUT %s]: Verifying pim join for group: %s"
2609 "[PASSED]!! Found Expected: (%s)",
2610 dut,
2611 grp_addr,
2612 data["channelJoinName"],
2613 )
2614 else:
2615 errormsg = (
2616 "[DUT %s]: Verifying pim join for group: %s"
2617 "[FAILED]!! Expected: (%s) "
2618 "Found: (%s)" % (dut, grp_addr, "JOIN", data["channelJoinName"])
2619 )
2620 return errormsg
2621
2622 if not pim_join:
2623 if data["group"] == grp_addr and data["channelJoinName"] == "NOINFO":
2624 logger.info(
2625 "[DUT %s]: Verifying pim join for group: %s"
2626 "[PASSED]!! Found Expected: (%s)",
2627 dut,
2628 grp_addr,
2629 data["channelJoinName"],
2630 )
2631 else:
2632 errormsg = (
2633 "[DUT %s]: Verifying pim join for group: %s"
2634 "[FAILED]!! Expected: (%s) "
2635 "Found: (%s)"
2636 % (dut, grp_addr, "NOINFO", data["channelJoinName"])
2637 )
2638 return errormsg
2639
2640 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2641 return True
2642
2643
2644@retry(attempts=31, wait=2, return_is_dict=True)
2645def verify_igmp_config(tgen, input_dict, stats_return=False):
2646 """
2647 Verify igmp interface details, verifying following configs:
2648 timerQueryInterval
2649 timerQueryResponseIntervalMsec
2650 lastMemberQueryCount
2651 timerLastMemberQueryMsec
2652
2653 Parameters
2654 ----------
2655 * `tgen`: topogen object
2656 * `input_dict` : Input dict data, required to verify
2657 timer
2658 * `stats_return`: If user wants API to return statistics
2659
2660 Usage
2661 -----
2662 input_dict ={
2663 "l1": {
2664 "igmp": {
2665 "interfaces": {
2666 "l1-i1-eth1": {
2667 "igmp": {
2668 "query": {
2669 "query-interval" : 200,
2670 "query-max-response-time" : 100
2671 },
2672 "statistics": {
2673 "queryV2" : 2,
2674 "reportV2" : 1
2675 }
2676 }
2677 }
2678 }
2679 }
2680 }
2681 }
2682 result = verify_igmp_config(tgen, input_dict, stats_return)
2683
2684 Returns
2685 -------
2686 errormsg(str) or True
2687 """
2688
2689 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2690
2691 for dut in input_dict.keys():
2692 rnode = tgen.routers()[dut]
2693
2694 for interface, data in input_dict[dut]["igmp"]["interfaces"].items():
2695
2696 statistics = False
2697 report = False
2698 if "statistics" in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"]:
2699 statistics = True
2700 cmd = "show ip igmp statistics"
2701 else:
2702 cmd = "show ip igmp"
2703
2704 logger.info(
2705 "[DUT: %s]: Verifying IGMP interface %s detail:", dut, interface
2706 )
2707
2708 if statistics:
2709 if (
2710 "report"
2711 in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"][
2712 "statistics"
2713 ]
2714 ):
2715 report = True
2716
2717 if statistics and report:
2718 show_ip_igmp_intf_json = run_frr_cmd(
2719 rnode, "{} json".format(cmd, interface), isjson=True
2720 )
2721 intf_detail_json = show_ip_igmp_intf_json["global"]
2722 else:
2723 show_ip_igmp_intf_json = run_frr_cmd(
2724 rnode, "{} interface {} json".format(cmd, interface), isjson=True
2725 )
2726
2727 if not report:
2728 if interface not in show_ip_igmp_intf_json:
2729 errormsg = (
2730 "[DUT %s]: IGMP interface: %s "
2731 " is not present in CLI output "
2732 "[FAILED]!! " % (dut, interface)
2733 )
2734 return errormsg
2735
2736 else:
2737 intf_detail_json = show_ip_igmp_intf_json[interface]
2738
2739 if stats_return:
2740 igmp_stats = {}
2741
2742 if "statistics" in data["igmp"]:
2743 if stats_return:
2744 igmp_stats["statistics"] = {}
2745 for query, value in data["igmp"]["statistics"].items():
2746 if query == "queryV2":
2747 # Verifying IGMP interface queryV2 statistics
2748 if stats_return:
2749 igmp_stats["statistics"][query] = intf_detail_json[
2750 "queryV2"
2751 ]
2752
2753 else:
2754 if intf_detail_json["queryV2"] != value:
2755 errormsg = (
2756 "[DUT %s]: IGMP interface: %s "
2757 " queryV2 statistics verification "
2758 "[FAILED]!! Expected : %s,"
2759 " Found : %s"
2760 % (
2761 dut,
2762 interface,
2763 value,
2764 intf_detail_json["queryV2"],
2765 )
2766 )
2767 return errormsg
2768
2769 logger.info(
2770 "[DUT %s]: IGMP interface: %s "
2771 "queryV2 statistics is %s",
2772 dut,
2773 interface,
2774 value,
2775 )
2776
2777 if query == "reportV2":
2778 # Verifying IGMP interface timerV2 statistics
2779 if stats_return:
2780 igmp_stats["statistics"][query] = intf_detail_json[
2781 "reportV2"
2782 ]
2783
2784 else:
2785 if intf_detail_json["reportV2"] <= value:
2786 errormsg = (
2787 "[DUT %s]: IGMP reportV2 "
2788 "statistics verification "
2789 "[FAILED]!! Expected : %s "
2790 "or more, Found : %s"
2791 % (
2792 dut,
2793 interface,
2794 value,
2795 intf_detail_json["reportV2"],
2796 )
2797 )
2798 return errormsg
2799
2800 logger.info(
2801 "[DUT %s]: IGMP reportV2 " "statistics is %s",
2802 dut,
2803 intf_detail_json["reportV2"],
2804 )
2805
2806 if "query" in data["igmp"]:
2807 for query, value in data["igmp"]["query"].items():
2808 if query == "query-interval":
2809 # Verifying IGMP interface query interval timer
2810 if intf_detail_json["timerQueryInterval"] != value:
2811 errormsg = (
2812 "[DUT %s]: IGMP interface: %s "
2813 " query-interval verification "
2814 "[FAILED]!! Expected : %s,"
2815 " Found : %s"
2816 % (
2817 dut,
2818 interface,
2819 value,
2820 intf_detail_json["timerQueryInterval"],
2821 )
2822 )
2823 return errormsg
2824
2825 logger.info(
2826 "[DUT %s]: IGMP interface: %s " "query-interval is %s",
2827 dut,
2828 interface,
2829 value,
2830 )
2831
2832 if query == "query-max-response-time":
2833 # Verifying IGMP interface query max response timer
2834 if (
2835 intf_detail_json["timerQueryResponseIntervalMsec"]
2836 != value * 100
2837 ):
2838 errormsg = (
2839 "[DUT %s]: IGMP interface: %s "
2840 "query-max-response-time "
2841 "verification [FAILED]!!"
2842 " Expected : %s, Found : %s"
2843 % (
2844 dut,
2845 interface,
2846 value * 1000,
2847 intf_detail_json["timerQueryResponseIntervalMsec"],
2848 )
2849 )
2850 return errormsg
2851
2852 logger.info(
2853 "[DUT %s]: IGMP interface: %s "
2854 "query-max-response-time is %s ms",
2855 dut,
2856 interface,
2857 value * 100,
2858 )
2859
2860 if query == "last-member-query-count":
2861 # Verifying IGMP interface last member query count
2862 if intf_detail_json["lastMemberQueryCount"] != value:
2863 errormsg = (
2864 "[DUT %s]: IGMP interface: %s "
2865 "last-member-query-count "
2866 "verification [FAILED]!!"
2867 " Expected : %s, Found : %s"
2868 % (
2869 dut,
2870 interface,
2871 value,
2872 intf_detail_json["lastMemberQueryCount"],
2873 )
2874 )
2875 return errormsg
2876
2877 logger.info(
2878 "[DUT %s]: IGMP interface: %s "
2879 "last-member-query-count is %s ms",
2880 dut,
2881 interface,
2882 value * 1000,
2883 )
2884
2885 if query == "last-member-query-interval":
2886 # Verifying IGMP interface last member query interval
2887 if (
2888 intf_detail_json["timerLastMemberQueryMsec"]
2889 != value * 100 * intf_detail_json["lastMemberQueryCount"]
2890 ):
2891 errormsg = (
2892 "[DUT %s]: IGMP interface: %s "
2893 "last-member-query-interval "
2894 "verification [FAILED]!!"
2895 " Expected : %s, Found : %s"
2896 % (
2897 dut,
2898 interface,
2899 value * 1000,
2900 intf_detail_json["timerLastMemberQueryMsec"],
2901 )
2902 )
2903 return errormsg
2904
2905 logger.info(
2906 "[DUT %s]: IGMP interface: %s "
2907 "last-member-query-interval is %s ms",
2908 dut,
2909 interface,
2910 value * intf_detail_json["lastMemberQueryCount"] * 100,
2911 )
2912
2913 if "version" in data["igmp"]:
2914 # Verifying IGMP interface state is up
2915 if intf_detail_json["state"] != "up":
2916 errormsg = (
2917 "[DUT %s]: IGMP interface: %s "
2918 " state: %s verification "
2919 "[FAILED]!!" % (dut, interface, intf_detail_json["state"])
2920 )
2921 return errormsg
2922
2923 logger.info(
2924 "[DUT %s]: IGMP interface: %s " "state: %s",
2925 dut,
2926 interface,
2927 intf_detail_json["state"],
2928 )
2929
2930 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2931 return True if stats_return == False else igmp_stats
2932
2933
2934@retry(attempts=31, wait=2, return_is_str=True)
2935def verify_pim_config(tgen, input_dict):
2936 """
2937 Verify pim interface details, verifying following configs:
2938 drPriority
2939 helloPeriod
2940 helloReceived
2941 helloSend
2942 drAddress
2943
2944 Parameters
2945 ----------
2946 * `tgen`: topogen object
2947 * `input_dict` : Input dict data, required to verify
2948 timer
2949
2950 Usage
2951 -----
2952 input_dict ={
2953 "l1": {
2954 "igmp": {
2955 "interfaces": {
2956 "l1-i1-eth1": {
2957 "pim": {
2958 "drPriority" : 10,
2959 "helloPeriod" : 5
2960 }
2961 }
2962 }
2963 }
2964 }
2965 }
2966 }
2967 result = verify_pim_config(tgen, input_dict)
2968
2969 Returns
2970 -------
2971 errormsg(str) or True
2972 """
2973
2974 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2975
2976 for dut in input_dict.keys():
2977 rnode = tgen.routers()[dut]
2978
2979 for interface, data in input_dict[dut]["pim"]["interfaces"].items():
2980
2981 logger.info("[DUT: %s]: Verifying PIM interface %s detail:", dut, interface)
2982
2983 show_ip_igmp_intf_json = run_frr_cmd(
2984 rnode, "show ip pim interface {} json".format(interface), isjson=True
2985 )
2986
2987 if interface not in show_ip_igmp_intf_json:
2988 errormsg = (
2989 "[DUT %s]: PIM interface: %s "
2990 " is not present in CLI output "
2991 "[FAILED]!! " % (dut, interface)
2992 )
2993 return errormsg
2994
2995 intf_detail_json = show_ip_igmp_intf_json[interface]
2996
2997 for config, value in data.items():
2998 if config == "helloPeriod":
2999 # Verifying PIM interface helloPeriod
3000 if intf_detail_json["helloPeriod"] != value:
3001 errormsg = (
3002 "[DUT %s]: PIM interface: %s "
3003 " helloPeriod verification "
3004 "[FAILED]!! Expected : %s,"
3005 " Found : %s"
3006 % (dut, interface, value, intf_detail_json["helloPeriod"])
3007 )
3008 return errormsg
3009
3010 logger.info(
3011 "[DUT %s]: PIM interface: %s " "helloPeriod is %s",
3012 dut,
3013 interface,
3014 value,
3015 )
3016
3017 if config == "drPriority":
3018 # Verifying PIM interface drPriority
3019 if intf_detail_json["drPriority"] != value:
3020 errormsg = (
3021 "[DUT %s]: PIM interface: %s "
3022 " drPriority verification "
3023 "[FAILED]!! Expected : %s,"
3024 " Found : %s"
3025 % (dut, interface, value, intf_detail_json["drPriority"])
3026 )
3027 return errormsg
3028
3029 logger.info(
3030 "[DUT %s]: PIM interface: %s " "drPriority is %s",
3031 dut,
3032 interface,
3033 value,
3034 )
3035
3036 if config == "drAddress":
3037 # Verifying PIM interface drAddress
3038 if intf_detail_json["drAddress"] != value:
3039 errormsg = (
3040 "[DUT %s]: PIM interface: %s "
3041 " drAddress verification "
3042 "[FAILED]!! Expected : %s,"
3043 " Found : %s"
3044 % (dut, interface, value, intf_detail_json["drAddress"])
3045 )
3046 return errormsg
3047
3048 logger.info(
3049 "[DUT %s]: PIM interface: %s " "drAddress is %s",
3050 dut,
3051 interface,
3052 value,
3053 )
3054
3055 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3056 return True
3057
3058
3059@retry(attempts=21, wait=2, return_is_dict=True)
3060def verify_multicast_traffic(tgen, input_dict, return_traffic=False):
3061 """
3062 Verify multicast traffic by running
3063 "show multicast traffic count json" cli
3064
3065 Parameters
3066 ----------
3067 * `tgen`: topogen object
3068 * `input_dict(dict)`: defines DUT, what and for which interfaces
3069 traffic needs to be verified
3070 * `return_traffic`: returns traffic stats
3071 Usage
3072 -----
3073 input_dict = {
3074 "r1": {
3075 "traffic_received": ["r1-r0-eth0"],
3076 "traffic_sent": ["r1-r0-eth0"]
3077 }
3078 }
3079
3080 result = verify_multicast_traffic(tgen, input_dict)
3081
3082 Returns
3083 -------
3084 errormsg(str) or True
3085 """
3086
3087 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3088
3089 traffic_dict = {}
3090 for dut in input_dict.keys():
3091 if dut not in tgen.routers():
3092 continue
3093
3094 rnode = tgen.routers()[dut]
3095
3096 logger.info("[DUT: %s]: Verifying multicast " "traffic", dut)
3097
3098 show_multicast_traffic_json = run_frr_cmd(
3099 rnode, "show ip multicast count json", isjson=True
3100 )
3101
3102 for traffic_type, interfaces in input_dict[dut].items():
3103 traffic_dict[traffic_type] = {}
3104 if traffic_type == "traffic_received":
3105 for interface in interfaces:
3106 traffic_dict[traffic_type][interface] = {}
3107 interface_json = show_multicast_traffic_json[interface]
3108
3109 if interface_json["pktsIn"] == 0 and interface_json["bytesIn"] == 0:
3110 errormsg = (
3111 "[DUT %s]: Multicast traffic is "
3112 "not received on interface %s "
3113 "PktsIn: %s, BytesIn: %s "
3114 "[FAILED]!!"
3115 % (
3116 dut,
3117 interface,
3118 interface_json["pktsIn"],
3119 interface_json["bytesIn"],
3120 )
3121 )
3122 return errormsg
3123
3124 elif (
3125 interface_json["pktsIn"] != 0 and interface_json["bytesIn"] != 0
3126 ):
3127
3128 traffic_dict[traffic_type][interface][
3129 "pktsIn"
3130 ] = interface_json["pktsIn"]
3131 traffic_dict[traffic_type][interface][
3132 "bytesIn"
3133 ] = interface_json["bytesIn"]
3134
3135 logger.info(
3136 "[DUT %s]: Multicast traffic is "
3137 "received on interface %s "
3138 "PktsIn: %s, BytesIn: %s "
3139 "[PASSED]!!"
3140 % (
3141 dut,
3142 interface,
3143 interface_json["pktsIn"],
3144 interface_json["bytesIn"],
3145 )
3146 )
3147
3148 else:
3149 errormsg = (
3150 "[DUT %s]: Multicast traffic interface %s:"
3151 " Miss-match in "
3152 "PktsIn: %s, BytesIn: %s"
3153 "[FAILED]!!"
3154 % (
3155 dut,
3156 interface,
3157 interface_json["pktsIn"],
3158 interface_json["bytesIn"],
3159 )
3160 )
3161 return errormsg
3162
3163 if traffic_type == "traffic_sent":
3164 traffic_dict[traffic_type] = {}
3165 for interface in interfaces:
3166 traffic_dict[traffic_type][interface] = {}
3167 interface_json = show_multicast_traffic_json[interface]
3168
3169 if (
3170 interface_json["pktsOut"] == 0
3171 and interface_json["bytesOut"] == 0
3172 ):
3173 errormsg = (
3174 "[DUT %s]: Multicast traffic is "
3175 "not received on interface %s "
3176 "PktsIn: %s, BytesIn: %s"
3177 "[FAILED]!!"
3178 % (
3179 dut,
3180 interface,
3181 interface_json["pktsOut"],
3182 interface_json["bytesOut"],
3183 )
3184 )
3185 return errormsg
3186
3187 elif (
3188 interface_json["pktsOut"] != 0
3189 and interface_json["bytesOut"] != 0
3190 ):
3191
3192 traffic_dict[traffic_type][interface][
3193 "pktsOut"
3194 ] = interface_json["pktsOut"]
3195 traffic_dict[traffic_type][interface][
3196 "bytesOut"
3197 ] = interface_json["bytesOut"]
3198
3199 logger.info(
3200 "[DUT %s]: Multicast traffic is "
3201 "received on interface %s "
3202 "PktsOut: %s, BytesOut: %s "
3203 "[PASSED]!!"
3204 % (
3205 dut,
3206 interface,
3207 interface_json["pktsOut"],
3208 interface_json["bytesOut"],
3209 )
3210 )
3211 else:
3212 errormsg = (
3213 "[DUT %s]: Multicast traffic interface %s:"
3214 " Miss-match in "
3215 "PktsOut: %s, BytesOut: %s "
3216 "[FAILED]!!"
3217 % (
3218 dut,
3219 interface,
3220 interface_json["pktsOut"],
3221 interface_json["bytesOut"],
3222 )
3223 )
3224 return errormsg
3225
3226 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3227 return True if return_traffic == False else traffic_dict
3228
3229
3230def get_refCount_for_mroute(tgen, dut, iif, src_address, group_addresses):
3231 """
3232 Verify upstream inbound interface is updated correctly
3233 by running "show ip pim upstream" cli
3234
3235 Parameters
3236 ----------
3237 * `tgen`: topogen object
3238 * `dut`: device under test
3239 * `iif`: inbound interface
3240 * `src_address`: source address
3241 * `group_addresses`: IGMP group address
3242
3243 Usage
3244 -----
3245 dut = "r1"
3246 iif = "r1-r0-eth0"
3247 src_address = "*"
3248 group_address = "225.1.1.1"
3249 result = get_refCount_for_mroute(tgen, dut, iif, src_address,
3250 group_address)
3251
3252 Returns
3253 -------
3254 refCount(int)
3255 """
3256
3257 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3258
3259 refCount = 0
3260 if dut not in tgen.routers():
3261 return False
3262
3263 rnode = tgen.routers()[dut]
3264
3265 logger.info("[DUT: %s]: Verifying refCount for mroutes: ", dut)
3266 show_ip_pim_upstream_json = run_frr_cmd(
3267 rnode, "show ip pim upstream json", isjson=True
3268 )
3269
3270 if type(group_addresses) is not list:
3271 group_addresses = [group_addresses]
3272
3273 for grp_addr in group_addresses:
3274 # Verify group address
3275 if grp_addr not in show_ip_pim_upstream_json:
3276 errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
3277 dut,
3278 grp_addr,
3279 )
3280 return errormsg
3281 group_addr_json = show_ip_pim_upstream_json[grp_addr]
3282
3283 # Verify source address
3284 if src_address not in group_addr_json:
3285 errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
3286 dut,
3287 src_address,
3288 grp_addr,
3289 )
3290 return errormsg
3291
3292 # Verify Inbound Interface
3293 if group_addr_json[src_address]["inboundInterface"] == iif:
3294 refCount = group_addr_json[src_address]["refCount"]
3295
3296 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3297 return refCount
3298
3299
3300@retry(attempts=21, wait=2, return_is_str=True)
3301def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
3302 """
3303 Verify flag state for mroutes and make sure (*, G)/(S, G) are having
3304 coorect flags by running "show ip mroute" cli
3305
3306 Parameters
3307 ----------
3308 * `tgen`: topogen object
3309 * `dut`: device under test
3310 * `src_address`: source address
3311 * `group_addresses`: IGMP group address
3312 * `flag`: flag state, needs to be verified
3313
3314 Usage
3315 -----
3316 dut = "r1"
3317 flag = "SC"
3318 group_address = "225.1.1.1"
3319 result = verify_multicast_flag_state(tgen, dut, src_address,
3320 group_address, flag)
3321
3322 Returns
3323 -------
3324 errormsg(str) or True
3325 """
3326
3327 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3328
3329 if dut not in tgen.routers():
3330 return False
3331
3332 rnode = tgen.routers()[dut]
3333
3334 logger.info("[DUT: %s]: Verifying flag state for mroutes", dut)
3335 show_ip_mroute_json = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
3336
3337 if bool(show_ip_mroute_json) == False:
3338 error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
3339 return error_msg
3340
3341 if type(group_addresses) is not list:
3342 group_addresses = [group_addresses]
3343
3344 for grp_addr in group_addresses:
3345 if grp_addr not in show_ip_mroute_json:
3346 errormsg = (
3347 "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! ",
3348 dut,
3349 src_address,
3350 grp_addr,
3351 )
3352 return errormsg
3353 else:
3354 group_addr_json = show_ip_mroute_json[grp_addr]
3355
3356 if src_address not in group_addr_json:
3357 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
3358 dut,
3359 src_address,
3360 grp_addr,
3361 )
3362 return errormsg
3363 else:
3364 mroutes = group_addr_json[src_address]
3365
3366 if mroutes["installed"] != 0:
3367 logger.info(
3368 "[DUT %s]: mroute (%s,%s) is installed", dut, src_address, grp_addr
3369 )
3370
3371 if mroutes["flags"] != flag:
3372 errormsg = (
3373 "[DUT %s]: Verifying flag for (%s, %s) "
3374 "mroute [FAILED]!! "
3375 "Expected: %s Found: %s"
3376 % (dut, src_address, grp_addr, flag, mroutes["flags"])
3377 )
3378 return errormsg
3379
3380 logger.info(
3381 "[DUT %s]: Verifying flag for (%s, %s)"
3382 " mroute, [PASSED]!! "
3383 "Found Expected: %s",
3384 dut,
3385 src_address,
3386 grp_addr,
3387 mroutes["flags"],
3388 )
3389
3390 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3391 return True
eab72dc8 3392
3393
3394@retry(attempts=21, wait=2, return_is_str=True)
3395def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip):
3396 """
3397 Verify all IGMP interface are up and running, config is verified
3398 using "show ip igmp interface" cli
3399
3400 Parameters
3401 ----------
3402 * `tgen`: topogen object
3403 * `topo` : json file data
3404 * `dut` : device under test
3405 * `igmp_iface` : interface name
3406 * `interface_ip` : interface ip address
3407
3408 Usage
3409 -----
3410 result = verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip)
3411
3412 Returns
3413 -------
3414 errormsg(str) or True
3415 """
3416
3417 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3418
3419 for router in tgen.routers():
3420 if router != dut:
3421 continue
3422
3423 logger.info("[DUT: %s]: Verifying PIM interface status:",
3424 dut)
3425
3426 rnode = tgen.routers()[dut]
3427 show_ip_igmp_interface_json = \
3428 run_frr_cmd(rnode, "show ip igmp interface json", isjson=True)
3429
3430 if igmp_iface in show_ip_igmp_interface_json:
3431 igmp_intf_json = show_ip_igmp_interface_json[igmp_iface]
3432 # Verifying igmp interface
3433 if igmp_intf_json["address"] != interface_ip:
3434 errormsg = ("[DUT %s]: igmp interface ip is not correct "
3435 "[FAILED]!! Expected : %s, Found : %s"
3436 %(dut, igmp_intf_json["address"], interface_ip))
3437 return errormsg
3438
3439 logger.info("[DUT %s]: igmp interface: %s, "
3440 "interface ip: %s"
3441 " [PASSED]!!",
3442 dut, igmp_iface, interface_ip)
3443 else:
3444 errormsg = ("[DUT %s]: igmp interface: %s "
3445 "igmp interface ip: %s, is not present "
3446 %(dut, igmp_iface, interface_ip))
3447 return errormsg
3448
3449 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3450 return True