]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/lib/pim.py
Merge pull request #8806 from donaldsharp/established
[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:
660c59ed 2380 rp_details = {dut: rp}
e8cd26fd 2381
2382 if dut in rp_details:
2383 pim_nh_intf_ip = topo["routers"][dut]["links"]["lo"]["ipv4"].split(
2384 "/"
2385 )[0]
2386 else:
2387 if destLink not in interface:
2388 continue
2389
2390 links = topo["routers"][destLink]["links"]
2391 pim_neighbor = {key: links[key] for key in [dut]}
2392
2393 data = pim_neighbor[dut]
2394 if "pim" in data and data["pim"] == "enable":
2395 pim_nh_intf_ip = data["ipv4"].split("/")[0]
2396
2397 upstream_rpf_json = show_ip_pim_upstream_rpf_json[grp_addr]["*"]
2398
2399 # Verifying ip pim upstream rpf
2400 if (
2401 upstream_rpf_json["rpfInterface"] == interface
2402 and upstream_rpf_json["ribNexthop"] != pim_nh_intf_ip
2403 ):
2404 errormsg = (
2405 "[DUT %s]: Verifying group: %s, "
2406 "rpf interface: %s, "
2407 " rib Nexthop check [FAILED]!!"
2408 "Expected: %s, Found: %s"
2409 % (
2410 dut,
2411 grp_addr,
2412 interface,
2413 pim_nh_intf_ip,
2414 upstream_rpf_json["ribNexthop"],
2415 )
2416 )
2417 return errormsg
2418
2419 logger.info(
2420 "[DUT %s]: Verifying group: %s,"
2421 " rpf interface: %s, "
2422 " rib Nexthop: %s [PASSED]!!",
2423 dut,
2424 grp_addr,
2425 interface,
2426 pim_nh_intf_ip,
2427 )
2428
2429 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2430 return True
2431
2432
2433def enable_disable_pim_unicast_bsm(tgen, router, intf, enable=True):
2434 """
2435 Helper API to enable or disable pim bsm on interfaces
2436
2437 Parameters
2438 ----------
2439 * `tgen` : Topogen object
2440 * `router` : router id to be configured.
2441 * `intf` : Interface to be configured
2442 * `enable` : this flag denotes if config should be enabled or disabled
2443
2444 Returns
2445 -------
2446 True or False
2447 """
2448 result = False
2449 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2450
2451 try:
2452 config_data = []
2453 cmd = "interface {}".format(intf)
2454 config_data.append(cmd)
2455
2456 if enable == True:
2457 config_data.append("ip pim unicast-bsm")
2458 else:
2459 config_data.append("no ip pim unicast-bsm")
2460
2461 result = create_common_configuration(
2462 tgen, router, config_data, "interface_config", build=False
2463 )
2464 if result is not True:
2465 return False
2466
2467 except InvalidCLIError:
2468 # Traceback
2469 errormsg = traceback.format_exc()
2470 logger.error(errormsg)
2471 return errormsg
2472
2473 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2474 return result
2475
2476
2477def enable_disable_pim_bsm(tgen, router, intf, enable=True):
2478 """
2479 Helper API to enable or disable pim bsm on interfaces
2480
2481 Parameters
2482 ----------
2483 * `tgen` : Topogen object
2484 * `router` : router id to be configured.
2485 * `intf` : Interface to be configured
2486 * `enable` : this flag denotes if config should be enabled or disabled
2487
2488 Returns
2489 -------
2490 True or False
2491 """
2492 result = False
2493 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2494
2495 try:
2496 config_data = []
2497 cmd = "interface {}".format(intf)
2498 config_data.append(cmd)
2499
2500 if enable is True:
2501 config_data.append("ip pim bsm")
2502 else:
2503 config_data.append("no ip pim bsm")
2504
2505 result = create_common_configuration(
2506 tgen, router, config_data, "interface_config", build=False
2507 )
2508 if result is not True:
2509 return False
2510
2511 except InvalidCLIError:
2512 # Traceback
2513 errormsg = traceback.format_exc()
2514 logger.error(errormsg)
2515 return errormsg
2516
2517 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2518 return result
2519
2520
2521@retry(attempts=31, wait=2, return_is_str=True)
2522def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=None):
2523 """
2524 Verify ip pim join by running "show ip pim join" cli
2525
2526 Parameters
2527 ----------
2528 * `tgen`: topogen object
2529 * `topo`: JSON file handler
2530 * `dut`: device under test
2531 * `interface`: interface name, from which PIM join would come
2532 * `group_addresses`: IGMP group address
2533 * `src_address`: Source address
2534
2535 Usage
2536 -----
2537 dut = "r1"
2538 interface = "r1-r0-eth0"
2539 group_address = "225.1.1.1"
2540 result = verify_ip_pim_join(tgen, dut, star, group_address, interface)
2541
2542 Returns
2543 -------
2544 errormsg(str) or True
2545 """
2546 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2547
2548 if dut not in tgen.routers():
2549 return False
2550
2551 rnode = tgen.routers()[dut]
2552
2553 logger.info("[DUT: %s]: Verifying pim join", dut)
2554 show_pim_join_json = run_frr_cmd(rnode, "show ip pim join json", isjson=True)
2555
2556 if type(group_addresses) is not list:
2557 group_addresses = [group_addresses]
2558
2559 for grp_addr in group_addresses:
2560 # Verify if IGMP is enabled in DUT
2561 if "igmp" not in topo["routers"][dut]:
2562 pim_join = True
2563 else:
2564 pim_join = False
2565
2566 interface_json = show_pim_join_json[interface]
2567
2568 grp_addr = grp_addr.split("/")[0]
2569 for source, data in interface_json[grp_addr].items():
2570
2571 # Verify pim join
2572 if pim_join:
2573 if data["group"] == grp_addr and data["channelJoinName"] == "JOIN":
2574 logger.info(
2575 "[DUT %s]: Verifying pim join for group: %s"
2576 "[PASSED]!! Found Expected: (%s)",
2577 dut,
2578 grp_addr,
2579 data["channelJoinName"],
2580 )
2581 else:
2582 errormsg = (
2583 "[DUT %s]: Verifying pim join for group: %s"
2584 "[FAILED]!! Expected: (%s) "
2585 "Found: (%s)" % (dut, grp_addr, "JOIN", data["channelJoinName"])
2586 )
2587 return errormsg
2588
2589 if not pim_join:
2590 if data["group"] == grp_addr and data["channelJoinName"] == "NOINFO":
2591 logger.info(
2592 "[DUT %s]: Verifying pim join for group: %s"
2593 "[PASSED]!! Found Expected: (%s)",
2594 dut,
2595 grp_addr,
2596 data["channelJoinName"],
2597 )
2598 else:
2599 errormsg = (
2600 "[DUT %s]: Verifying pim join for group: %s"
2601 "[FAILED]!! Expected: (%s) "
2602 "Found: (%s)"
2603 % (dut, grp_addr, "NOINFO", data["channelJoinName"])
2604 )
2605 return errormsg
2606
2607 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2608 return True
2609
2610
2611@retry(attempts=31, wait=2, return_is_dict=True)
2612def verify_igmp_config(tgen, input_dict, stats_return=False):
2613 """
2614 Verify igmp interface details, verifying following configs:
2615 timerQueryInterval
2616 timerQueryResponseIntervalMsec
2617 lastMemberQueryCount
2618 timerLastMemberQueryMsec
2619
2620 Parameters
2621 ----------
2622 * `tgen`: topogen object
2623 * `input_dict` : Input dict data, required to verify
2624 timer
2625 * `stats_return`: If user wants API to return statistics
2626
2627 Usage
2628 -----
2629 input_dict ={
2630 "l1": {
2631 "igmp": {
2632 "interfaces": {
2633 "l1-i1-eth1": {
2634 "igmp": {
2635 "query": {
2636 "query-interval" : 200,
2637 "query-max-response-time" : 100
2638 },
2639 "statistics": {
2640 "queryV2" : 2,
2641 "reportV2" : 1
2642 }
2643 }
2644 }
2645 }
2646 }
2647 }
2648 }
2649 result = verify_igmp_config(tgen, input_dict, stats_return)
2650
2651 Returns
2652 -------
2653 errormsg(str) or True
2654 """
2655
2656 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2657
2658 for dut in input_dict.keys():
2659 rnode = tgen.routers()[dut]
2660
2661 for interface, data in input_dict[dut]["igmp"]["interfaces"].items():
2662
2663 statistics = False
2664 report = False
2665 if "statistics" in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"]:
2666 statistics = True
2667 cmd = "show ip igmp statistics"
2668 else:
2669 cmd = "show ip igmp"
2670
2671 logger.info(
2672 "[DUT: %s]: Verifying IGMP interface %s detail:", dut, interface
2673 )
2674
2675 if statistics:
2676 if (
2677 "report"
2678 in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"][
2679 "statistics"
2680 ]
2681 ):
2682 report = True
2683
2684 if statistics and report:
2685 show_ip_igmp_intf_json = run_frr_cmd(
5aab262b 2686 rnode, "{} json".format(cmd), isjson=True
e8cd26fd 2687 )
2688 intf_detail_json = show_ip_igmp_intf_json["global"]
2689 else:
2690 show_ip_igmp_intf_json = run_frr_cmd(
2691 rnode, "{} interface {} json".format(cmd, interface), isjson=True
2692 )
2693
2694 if not report:
2695 if interface not in show_ip_igmp_intf_json:
2696 errormsg = (
2697 "[DUT %s]: IGMP interface: %s "
2698 " is not present in CLI output "
2699 "[FAILED]!! " % (dut, interface)
2700 )
2701 return errormsg
2702
2703 else:
2704 intf_detail_json = show_ip_igmp_intf_json[interface]
2705
2706 if stats_return:
2707 igmp_stats = {}
2708
2709 if "statistics" in data["igmp"]:
2710 if stats_return:
2711 igmp_stats["statistics"] = {}
2712 for query, value in data["igmp"]["statistics"].items():
2713 if query == "queryV2":
2714 # Verifying IGMP interface queryV2 statistics
2715 if stats_return:
2716 igmp_stats["statistics"][query] = intf_detail_json[
2717 "queryV2"
2718 ]
2719
2720 else:
2721 if intf_detail_json["queryV2"] != value:
2722 errormsg = (
2723 "[DUT %s]: IGMP interface: %s "
2724 " queryV2 statistics verification "
2725 "[FAILED]!! Expected : %s,"
2726 " Found : %s"
2727 % (
2728 dut,
2729 interface,
2730 value,
2731 intf_detail_json["queryV2"],
2732 )
2733 )
2734 return errormsg
2735
2736 logger.info(
2737 "[DUT %s]: IGMP interface: %s "
2738 "queryV2 statistics is %s",
2739 dut,
2740 interface,
2741 value,
2742 )
2743
2744 if query == "reportV2":
2745 # Verifying IGMP interface timerV2 statistics
2746 if stats_return:
2747 igmp_stats["statistics"][query] = intf_detail_json[
2748 "reportV2"
2749 ]
2750
2751 else:
2752 if intf_detail_json["reportV2"] <= value:
2753 errormsg = (
2754 "[DUT %s]: IGMP reportV2 "
2755 "statistics verification "
2756 "[FAILED]!! Expected : %s "
2757 "or more, Found : %s"
2758 % (
2759 dut,
2760 interface,
2761 value,
e8cd26fd 2762 )
2763 )
2764 return errormsg
2765
2766 logger.info(
2767 "[DUT %s]: IGMP reportV2 " "statistics is %s",
2768 dut,
2769 intf_detail_json["reportV2"],
2770 )
2771
2772 if "query" in data["igmp"]:
2773 for query, value in data["igmp"]["query"].items():
2774 if query == "query-interval":
2775 # Verifying IGMP interface query interval timer
2776 if intf_detail_json["timerQueryInterval"] != value:
2777 errormsg = (
2778 "[DUT %s]: IGMP interface: %s "
2779 " query-interval verification "
2780 "[FAILED]!! Expected : %s,"
2781 " Found : %s"
2782 % (
2783 dut,
2784 interface,
2785 value,
2786 intf_detail_json["timerQueryInterval"],
2787 )
2788 )
2789 return errormsg
2790
2791 logger.info(
2792 "[DUT %s]: IGMP interface: %s " "query-interval is %s",
2793 dut,
2794 interface,
2795 value,
2796 )
2797
2798 if query == "query-max-response-time":
2799 # Verifying IGMP interface query max response timer
2800 if (
2801 intf_detail_json["timerQueryResponseIntervalMsec"]
2802 != value * 100
2803 ):
2804 errormsg = (
2805 "[DUT %s]: IGMP interface: %s "
2806 "query-max-response-time "
2807 "verification [FAILED]!!"
2808 " Expected : %s, Found : %s"
2809 % (
2810 dut,
2811 interface,
2812 value * 1000,
2813 intf_detail_json["timerQueryResponseIntervalMsec"],
2814 )
2815 )
2816 return errormsg
2817
2818 logger.info(
2819 "[DUT %s]: IGMP interface: %s "
2820 "query-max-response-time is %s ms",
2821 dut,
2822 interface,
2823 value * 100,
2824 )
2825
2826 if query == "last-member-query-count":
2827 # Verifying IGMP interface last member query count
2828 if intf_detail_json["lastMemberQueryCount"] != value:
2829 errormsg = (
2830 "[DUT %s]: IGMP interface: %s "
2831 "last-member-query-count "
2832 "verification [FAILED]!!"
2833 " Expected : %s, Found : %s"
2834 % (
2835 dut,
2836 interface,
2837 value,
2838 intf_detail_json["lastMemberQueryCount"],
2839 )
2840 )
2841 return errormsg
2842
2843 logger.info(
2844 "[DUT %s]: IGMP interface: %s "
2845 "last-member-query-count is %s ms",
2846 dut,
2847 interface,
2848 value * 1000,
2849 )
2850
2851 if query == "last-member-query-interval":
2852 # Verifying IGMP interface last member query interval
2853 if (
2854 intf_detail_json["timerLastMemberQueryMsec"]
2855 != value * 100 * intf_detail_json["lastMemberQueryCount"]
2856 ):
2857 errormsg = (
2858 "[DUT %s]: IGMP interface: %s "
2859 "last-member-query-interval "
2860 "verification [FAILED]!!"
2861 " Expected : %s, Found : %s"
2862 % (
2863 dut,
2864 interface,
2865 value * 1000,
2866 intf_detail_json["timerLastMemberQueryMsec"],
2867 )
2868 )
2869 return errormsg
2870
2871 logger.info(
2872 "[DUT %s]: IGMP interface: %s "
2873 "last-member-query-interval is %s ms",
2874 dut,
2875 interface,
2876 value * intf_detail_json["lastMemberQueryCount"] * 100,
2877 )
2878
2879 if "version" in data["igmp"]:
2880 # Verifying IGMP interface state is up
2881 if intf_detail_json["state"] != "up":
2882 errormsg = (
2883 "[DUT %s]: IGMP interface: %s "
2884 " state: %s verification "
2885 "[FAILED]!!" % (dut, interface, intf_detail_json["state"])
2886 )
2887 return errormsg
2888
2889 logger.info(
2890 "[DUT %s]: IGMP interface: %s " "state: %s",
2891 dut,
2892 interface,
2893 intf_detail_json["state"],
2894 )
2895
2896 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2897 return True if stats_return == False else igmp_stats
2898
2899
2900@retry(attempts=31, wait=2, return_is_str=True)
2901def verify_pim_config(tgen, input_dict):
2902 """
2903 Verify pim interface details, verifying following configs:
2904 drPriority
2905 helloPeriod
2906 helloReceived
2907 helloSend
2908 drAddress
2909
2910 Parameters
2911 ----------
2912 * `tgen`: topogen object
2913 * `input_dict` : Input dict data, required to verify
2914 timer
2915
2916 Usage
2917 -----
2918 input_dict ={
2919 "l1": {
2920 "igmp": {
2921 "interfaces": {
2922 "l1-i1-eth1": {
2923 "pim": {
2924 "drPriority" : 10,
2925 "helloPeriod" : 5
2926 }
2927 }
2928 }
2929 }
2930 }
2931 }
2932 }
2933 result = verify_pim_config(tgen, input_dict)
2934
2935 Returns
2936 -------
2937 errormsg(str) or True
2938 """
2939
2940 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2941
2942 for dut in input_dict.keys():
2943 rnode = tgen.routers()[dut]
2944
2945 for interface, data in input_dict[dut]["pim"]["interfaces"].items():
2946
2947 logger.info("[DUT: %s]: Verifying PIM interface %s detail:", dut, interface)
2948
2949 show_ip_igmp_intf_json = run_frr_cmd(
2950 rnode, "show ip pim interface {} json".format(interface), isjson=True
2951 )
2952
2953 if interface not in show_ip_igmp_intf_json:
2954 errormsg = (
2955 "[DUT %s]: PIM interface: %s "
2956 " is not present in CLI output "
2957 "[FAILED]!! " % (dut, interface)
2958 )
2959 return errormsg
2960
2961 intf_detail_json = show_ip_igmp_intf_json[interface]
2962
2963 for config, value in data.items():
2964 if config == "helloPeriod":
2965 # Verifying PIM interface helloPeriod
2966 if intf_detail_json["helloPeriod"] != value:
2967 errormsg = (
2968 "[DUT %s]: PIM interface: %s "
2969 " helloPeriod verification "
2970 "[FAILED]!! Expected : %s,"
2971 " Found : %s"
2972 % (dut, interface, value, intf_detail_json["helloPeriod"])
2973 )
2974 return errormsg
2975
2976 logger.info(
2977 "[DUT %s]: PIM interface: %s " "helloPeriod is %s",
2978 dut,
2979 interface,
2980 value,
2981 )
2982
2983 if config == "drPriority":
2984 # Verifying PIM interface drPriority
2985 if intf_detail_json["drPriority"] != value:
2986 errormsg = (
2987 "[DUT %s]: PIM interface: %s "
2988 " drPriority verification "
2989 "[FAILED]!! Expected : %s,"
2990 " Found : %s"
2991 % (dut, interface, value, intf_detail_json["drPriority"])
2992 )
2993 return errormsg
2994
2995 logger.info(
2996 "[DUT %s]: PIM interface: %s " "drPriority is %s",
2997 dut,
2998 interface,
2999 value,
3000 )
3001
3002 if config == "drAddress":
3003 # Verifying PIM interface drAddress
3004 if intf_detail_json["drAddress"] != value:
3005 errormsg = (
3006 "[DUT %s]: PIM interface: %s "
3007 " drAddress verification "
3008 "[FAILED]!! Expected : %s,"
3009 " Found : %s"
3010 % (dut, interface, value, intf_detail_json["drAddress"])
3011 )
3012 return errormsg
3013
3014 logger.info(
3015 "[DUT %s]: PIM interface: %s " "drAddress is %s",
3016 dut,
3017 interface,
3018 value,
3019 )
3020
3021 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3022 return True
3023
3024
3025@retry(attempts=21, wait=2, return_is_dict=True)
3026def verify_multicast_traffic(tgen, input_dict, return_traffic=False):
3027 """
3028 Verify multicast traffic by running
3029 "show multicast traffic count json" cli
3030
3031 Parameters
3032 ----------
3033 * `tgen`: topogen object
3034 * `input_dict(dict)`: defines DUT, what and for which interfaces
3035 traffic needs to be verified
3036 * `return_traffic`: returns traffic stats
3037 Usage
3038 -----
3039 input_dict = {
3040 "r1": {
3041 "traffic_received": ["r1-r0-eth0"],
3042 "traffic_sent": ["r1-r0-eth0"]
3043 }
3044 }
3045
3046 result = verify_multicast_traffic(tgen, input_dict)
3047
3048 Returns
3049 -------
3050 errormsg(str) or True
3051 """
3052
3053 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3054
3055 traffic_dict = {}
3056 for dut in input_dict.keys():
3057 if dut not in tgen.routers():
3058 continue
3059
3060 rnode = tgen.routers()[dut]
3061
3062 logger.info("[DUT: %s]: Verifying multicast " "traffic", dut)
3063
3064 show_multicast_traffic_json = run_frr_cmd(
3065 rnode, "show ip multicast count json", isjson=True
3066 )
3067
3068 for traffic_type, interfaces in input_dict[dut].items():
3069 traffic_dict[traffic_type] = {}
3070 if traffic_type == "traffic_received":
3071 for interface in interfaces:
3072 traffic_dict[traffic_type][interface] = {}
3073 interface_json = show_multicast_traffic_json[interface]
3074
3075 if interface_json["pktsIn"] == 0 and interface_json["bytesIn"] == 0:
3076 errormsg = (
3077 "[DUT %s]: Multicast traffic is "
3078 "not received on interface %s "
3079 "PktsIn: %s, BytesIn: %s "
3080 "[FAILED]!!"
3081 % (
3082 dut,
3083 interface,
3084 interface_json["pktsIn"],
3085 interface_json["bytesIn"],
3086 )
3087 )
3088 return errormsg
3089
3090 elif (
3091 interface_json["pktsIn"] != 0 and interface_json["bytesIn"] != 0
3092 ):
3093
3094 traffic_dict[traffic_type][interface][
3095 "pktsIn"
3096 ] = interface_json["pktsIn"]
3097 traffic_dict[traffic_type][interface][
3098 "bytesIn"
3099 ] = interface_json["bytesIn"]
3100
3101 logger.info(
3102 "[DUT %s]: Multicast traffic is "
3103 "received on interface %s "
3104 "PktsIn: %s, BytesIn: %s "
3105 "[PASSED]!!"
3106 % (
3107 dut,
3108 interface,
3109 interface_json["pktsIn"],
3110 interface_json["bytesIn"],
3111 )
3112 )
3113
3114 else:
3115 errormsg = (
3116 "[DUT %s]: Multicast traffic interface %s:"
3117 " Miss-match in "
3118 "PktsIn: %s, BytesIn: %s"
3119 "[FAILED]!!"
3120 % (
3121 dut,
3122 interface,
3123 interface_json["pktsIn"],
3124 interface_json["bytesIn"],
3125 )
3126 )
3127 return errormsg
3128
3129 if traffic_type == "traffic_sent":
3130 traffic_dict[traffic_type] = {}
3131 for interface in interfaces:
3132 traffic_dict[traffic_type][interface] = {}
3133 interface_json = show_multicast_traffic_json[interface]
3134
3135 if (
3136 interface_json["pktsOut"] == 0
3137 and interface_json["bytesOut"] == 0
3138 ):
3139 errormsg = (
3140 "[DUT %s]: Multicast traffic is "
3141 "not received on interface %s "
3142 "PktsIn: %s, BytesIn: %s"
3143 "[FAILED]!!"
3144 % (
3145 dut,
3146 interface,
3147 interface_json["pktsOut"],
3148 interface_json["bytesOut"],
3149 )
3150 )
3151 return errormsg
3152
3153 elif (
3154 interface_json["pktsOut"] != 0
3155 and interface_json["bytesOut"] != 0
3156 ):
3157
3158 traffic_dict[traffic_type][interface][
3159 "pktsOut"
3160 ] = interface_json["pktsOut"]
3161 traffic_dict[traffic_type][interface][
3162 "bytesOut"
3163 ] = interface_json["bytesOut"]
3164
3165 logger.info(
3166 "[DUT %s]: Multicast traffic is "
3167 "received on interface %s "
3168 "PktsOut: %s, BytesOut: %s "
3169 "[PASSED]!!"
3170 % (
3171 dut,
3172 interface,
3173 interface_json["pktsOut"],
3174 interface_json["bytesOut"],
3175 )
3176 )
3177 else:
3178 errormsg = (
3179 "[DUT %s]: Multicast traffic interface %s:"
3180 " Miss-match in "
3181 "PktsOut: %s, BytesOut: %s "
3182 "[FAILED]!!"
3183 % (
3184 dut,
3185 interface,
3186 interface_json["pktsOut"],
3187 interface_json["bytesOut"],
3188 )
3189 )
3190 return errormsg
3191
3192 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3193 return True if return_traffic == False else traffic_dict
3194
3195
3196def get_refCount_for_mroute(tgen, dut, iif, src_address, group_addresses):
3197 """
3198 Verify upstream inbound interface is updated correctly
3199 by running "show ip pim upstream" cli
3200
3201 Parameters
3202 ----------
3203 * `tgen`: topogen object
3204 * `dut`: device under test
3205 * `iif`: inbound interface
3206 * `src_address`: source address
3207 * `group_addresses`: IGMP group address
3208
3209 Usage
3210 -----
3211 dut = "r1"
3212 iif = "r1-r0-eth0"
3213 src_address = "*"
3214 group_address = "225.1.1.1"
3215 result = get_refCount_for_mroute(tgen, dut, iif, src_address,
3216 group_address)
3217
3218 Returns
3219 -------
3220 refCount(int)
3221 """
3222
3223 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3224
3225 refCount = 0
3226 if dut not in tgen.routers():
3227 return False
3228
3229 rnode = tgen.routers()[dut]
3230
3231 logger.info("[DUT: %s]: Verifying refCount for mroutes: ", dut)
3232 show_ip_pim_upstream_json = run_frr_cmd(
3233 rnode, "show ip pim upstream json", isjson=True
3234 )
3235
3236 if type(group_addresses) is not list:
3237 group_addresses = [group_addresses]
3238
3239 for grp_addr in group_addresses:
3240 # Verify group address
3241 if grp_addr not in show_ip_pim_upstream_json:
3242 errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
3243 dut,
3244 grp_addr,
3245 )
3246 return errormsg
3247 group_addr_json = show_ip_pim_upstream_json[grp_addr]
3248
3249 # Verify source address
3250 if src_address not in group_addr_json:
3251 errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
3252 dut,
3253 src_address,
3254 grp_addr,
3255 )
3256 return errormsg
3257
3258 # Verify Inbound Interface
3259 if group_addr_json[src_address]["inboundInterface"] == iif:
3260 refCount = group_addr_json[src_address]["refCount"]
3261
3262 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3263 return refCount
3264
3265
3266@retry(attempts=21, wait=2, return_is_str=True)
3267def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag):
3268 """
3269 Verify flag state for mroutes and make sure (*, G)/(S, G) are having
3270 coorect flags by running "show ip mroute" cli
3271
3272 Parameters
3273 ----------
3274 * `tgen`: topogen object
3275 * `dut`: device under test
3276 * `src_address`: source address
3277 * `group_addresses`: IGMP group address
3278 * `flag`: flag state, needs to be verified
3279
3280 Usage
3281 -----
3282 dut = "r1"
3283 flag = "SC"
3284 group_address = "225.1.1.1"
3285 result = verify_multicast_flag_state(tgen, dut, src_address,
3286 group_address, flag)
3287
3288 Returns
3289 -------
3290 errormsg(str) or True
3291 """
3292
3293 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3294
3295 if dut not in tgen.routers():
3296 return False
3297
3298 rnode = tgen.routers()[dut]
3299
3300 logger.info("[DUT: %s]: Verifying flag state for mroutes", dut)
3301 show_ip_mroute_json = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
3302
3303 if bool(show_ip_mroute_json) == False:
3304 error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
3305 return error_msg
3306
3307 if type(group_addresses) is not list:
3308 group_addresses = [group_addresses]
3309
3310 for grp_addr in group_addresses:
3311 if grp_addr not in show_ip_mroute_json:
3312 errormsg = (
3313 "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! ",
3314 dut,
3315 src_address,
3316 grp_addr,
3317 )
3318 return errormsg
3319 else:
3320 group_addr_json = show_ip_mroute_json[grp_addr]
3321
3322 if src_address not in group_addr_json:
3323 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
3324 dut,
3325 src_address,
3326 grp_addr,
3327 )
3328 return errormsg
3329 else:
3330 mroutes = group_addr_json[src_address]
3331
3332 if mroutes["installed"] != 0:
3333 logger.info(
3334 "[DUT %s]: mroute (%s,%s) is installed", dut, src_address, grp_addr
3335 )
3336
3337 if mroutes["flags"] != flag:
3338 errormsg = (
3339 "[DUT %s]: Verifying flag for (%s, %s) "
3340 "mroute [FAILED]!! "
3341 "Expected: %s Found: %s"
3342 % (dut, src_address, grp_addr, flag, mroutes["flags"])
3343 )
3344 return errormsg
3345
3346 logger.info(
3347 "[DUT %s]: Verifying flag for (%s, %s)"
3348 " mroute, [PASSED]!! "
3349 "Found Expected: %s",
3350 dut,
3351 src_address,
3352 grp_addr,
3353 mroutes["flags"],
3354 )
3355
3356 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3357 return True
eab72dc8 3358
3359
3360@retry(attempts=21, wait=2, return_is_str=True)
3361def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip):
3362 """
3363 Verify all IGMP interface are up and running, config is verified
3364 using "show ip igmp interface" cli
3365
3366 Parameters
3367 ----------
3368 * `tgen`: topogen object
3369 * `topo` : json file data
3370 * `dut` : device under test
3371 * `igmp_iface` : interface name
3372 * `interface_ip` : interface ip address
3373
3374 Usage
3375 -----
3376 result = verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip)
3377
3378 Returns
3379 -------
3380 errormsg(str) or True
3381 """
3382
3383 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3384
3385 for router in tgen.routers():
3386 if router != dut:
3387 continue
3388
5980ad0a 3389 logger.info("[DUT: %s]: Verifying PIM interface status:", dut)
eab72dc8 3390
3391 rnode = tgen.routers()[dut]
5980ad0a
DS
3392 show_ip_igmp_interface_json = run_frr_cmd(
3393 rnode, "show ip igmp interface json", isjson=True
3394 )
eab72dc8 3395
5980ad0a 3396 if igmp_iface in show_ip_igmp_interface_json:
eab72dc8 3397 igmp_intf_json = show_ip_igmp_interface_json[igmp_iface]
3398 # Verifying igmp interface
5980ad0a
DS
3399 if igmp_intf_json["address"] != interface_ip:
3400 errormsg = (
3401 "[DUT %s]: igmp interface ip is not correct "
3402 "[FAILED]!! Expected : %s, Found : %s"
3403 % (dut, igmp_intf_json["address"], interface_ip)
3404 )
eab72dc8 3405 return errormsg
3406
5980ad0a
DS
3407 logger.info(
3408 "[DUT %s]: igmp interface: %s, " "interface ip: %s" " [PASSED]!!",
3409 dut,
3410 igmp_iface,
3411 interface_ip,
3412 )
eab72dc8 3413 else:
5980ad0a
DS
3414 errormsg = (
3415 "[DUT %s]: igmp interface: %s "
3416 "igmp interface ip: %s, is not present "
3417 % (dut, igmp_iface, interface_ip)
3418 )
eab72dc8 3419 return errormsg
3420
3421 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3422 return True