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