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