]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/lib/pim.py
*: manual SPDX License ID conversions
[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
3d7d6e9a 24import functools
e8cd26fd 25from copy import deepcopy
49581587 26from time import sleep
3d7d6e9a 27from lib import topotest
49581587 28
e8cd26fd 29
30# Import common_config to use commomnly used APIs
31from lib.common_config import (
4f99894d 32 create_common_configurations,
a5124c49
CH
33 HostApplicationHelper,
34 InvalidCLIError,
49581587 35 create_common_configuration,
e8cd26fd 36 InvalidCLIError,
37 retry,
38 run_frr_cmd,
e13f9c4f 39 validate_ip_address,
d7032129 40 get_frr_ipv6_linklocal,
e8cd26fd 41)
4953ca97 42from lib.micronet import get_exec_path
49581587 43from lib.topolog import logger
a5124c49 44from lib.topotest import frr_unicode
e8cd26fd 45
46####
47CWD = os.path.dirname(os.path.realpath(__file__))
48
49
50def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True):
51 """
d7032129 52 API to configure pim/pim6 on router
e8cd26fd 53
54 Parameters
55 ----------
56 * `tgen` : Topogen object
57 * `topo` : json file data
58 * `input_dict` : Input dict data, required when configuring from
59 testcase
60 * `build` : Only for initial setup phase this is set as True.
61
62 Usage
63 -----
64 input_dict = {
65 "r1": {
66 "pim": {
0a76e764 67 "join-prune-interval": "5",
e8cd26fd 68 "rp": [{
69 "rp_addr" : "1.0.3.17".
70 "keep-alive-timer": "100"
71 "group_addr_range": ["224.1.1.0/24", "225.1.1.0/24"]
72 "prefix-list": "pf_list_1"
73 "delete": True
74 }]
e13f9c4f
KK
75 },
76 "pim6": {
77 "disable" : ["l1-i1-eth1"],
78 "rp": [{
79 "rp_addr" : "2001:db8:f::5:17".
80 "keep-alive-timer": "100"
81 "group_addr_range": ["FF00::/8"]
82 "prefix-list": "pf_list_1"
83 "delete": True
84 }]
e8cd26fd 85 }
86 }
87 }
88
89
90 Returns
91 -------
92 True or False
93 """
94 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
95 result = False
96 if not input_dict:
97 input_dict = deepcopy(topo)
98 else:
99 topo = topo["routers"]
100 input_dict = deepcopy(input_dict)
4f99894d
CH
101
102 config_data_dict = {}
103
e8cd26fd 104 for router in input_dict.keys():
4f99894d 105 config_data = _enable_disable_pim_config(tgen, topo, input_dict, router, build)
e8cd26fd 106
4f99894d
CH
107 if config_data:
108 config_data_dict[router] = config_data
109
110 # Now add RP config to all routers
111 for router in input_dict.keys():
e13f9c4f
KK
112 if "pim" in input_dict[router] or "pim6" in input_dict[router]:
113 _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict)
4f99894d
CH
114 try:
115 result = create_common_configurations(
116 tgen, config_data_dict, "pim", build, load_config
117 )
118 except InvalidCLIError:
119 logger.error("create_pim_config", exc_info=True)
120 result = False
e8cd26fd 121
122 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
123 return result
124
125
4f99894d 126def _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict):
e8cd26fd 127 """
0a76e764 128 Helper API to create pim RP configurations.
e8cd26fd 129
130 Parameters
131 ----------
132 * `tgen` : Topogen object
133 * `topo` : json file data
134 * `input_dict` : Input dict data, required when configuring from testcase
135 * `router` : router id to be configured.
136 * `build` : Only for initial setup phase this is set as True.
4f99894d 137 * `config_data_dict` : OUT: adds `router` config to dictinary
e8cd26fd 138 Returns
139 -------
4f99894d 140 None
e8cd26fd 141 """
142
e8cd26fd 143 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
e13f9c4f
KK
144 rp_data = []
145
146 # PIMv4
147 pim_data = None
148 if "pim" in input_dict[router]:
149 pim_data = input_dict[router]["pim"]
150 if "rp" in input_dict[router]["pim"]:
151 rp_data += pim_data["rp"]
e8cd26fd 152
d7032129 153 # pim6
e13f9c4f
KK
154 pim6_data = None
155 if "pim6" in input_dict[router]:
156 pim6_data = input_dict[router]["pim6"]
157 if "rp" in input_dict[router]["pim6"]:
158 rp_data += pim6_data["rp"]
e8cd26fd 159
0a76e764
CH
160 # Configure this RP on every router.
161 for dut in tgen.routers():
0a76e764
CH
162 # At least one interface must be enabled for PIM on the router
163 pim_if_enabled = False
e13f9c4f 164 pim6_if_enabled = False
0a76e764
CH
165 for destLink, data in topo[dut]["links"].items():
166 if "pim" in data:
167 pim_if_enabled = True
e13f9c4f
KK
168 if "pim6" in data:
169 pim6_if_enabled = True
170 if not pim_if_enabled and pim_data:
171 continue
172 if not pim6_if_enabled and pim6_data:
0a76e764 173 continue
e8cd26fd 174
0a76e764 175 config_data = []
e8cd26fd 176
e13f9c4f
KK
177 if rp_data:
178 for rp_dict in deepcopy(rp_data):
179 # ip address of RP
180 if "rp_addr" not in rp_dict and build:
181 logger.error(
182 "Router %s: 'ip address of RP' not "
183 "present in input_dict/JSON",
184 router,
185 )
e8cd26fd 186
e13f9c4f
KK
187 return False
188 rp_addr = rp_dict.setdefault("rp_addr", None)
189 if rp_addr:
190 addr_type = validate_ip_address(rp_addr)
191 # Keep alive Timer
192 keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None)
193
194 # Group Address range to cover
195 if "group_addr_range" not in rp_dict and build:
196 logger.error(
197 "Router %s:'Group Address range to cover'"
198 " not present in input_dict/JSON",
199 router,
200 )
e8cd26fd 201
e13f9c4f
KK
202 return False
203 group_addr_range = rp_dict.setdefault("group_addr_range", None)
e8cd26fd 204
e13f9c4f
KK
205 # Group prefix-list filter
206 prefix_list = rp_dict.setdefault("prefix_list", None)
e8cd26fd 207
e13f9c4f
KK
208 # Delete rp config
209 del_action = rp_dict.setdefault("delete", False)
0a76e764 210
e13f9c4f
KK
211 if keep_alive_timer:
212 if addr_type == "ipv4":
213 cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer)
214 if del_action:
215 cmd = "no {}".format(cmd)
216 config_data.append(cmd)
217 if addr_type == "ipv6":
218 cmd = "ipv6 pim rp keep-alive-timer {}".format(keep_alive_timer)
e8cd26fd 219 if del_action:
220 cmd = "no {}".format(cmd)
0a76e764 221 config_data.append(cmd)
e8cd26fd 222
e13f9c4f
KK
223 if rp_addr:
224 if group_addr_range:
225 if type(group_addr_range) is not list:
226 group_addr_range = [group_addr_range]
e8cd26fd 227
e13f9c4f
KK
228 for grp_addr in group_addr_range:
229 if addr_type == "ipv4":
230 cmd = "ip pim rp {} {}".format(rp_addr, grp_addr)
231 if del_action:
232 cmd = "no {}".format(cmd)
233 config_data.append(cmd)
234 if addr_type == "ipv6":
235 cmd = "ipv6 pim rp {} {}".format(rp_addr, grp_addr)
236 if del_action:
237 cmd = "no {}".format(cmd)
238 config_data.append(cmd)
239
240 if prefix_list:
241 if addr_type == "ipv4":
242 cmd = "ip pim rp {} prefix-list {}".format(
243 rp_addr, prefix_list
244 )
245 if del_action:
246 cmd = "no {}".format(cmd)
247 config_data.append(cmd)
248 if addr_type == "ipv6":
249 cmd = "ipv6 pim rp {} prefix-list {}".format(
250 rp_addr, prefix_list
251 )
252 if del_action:
253 cmd = "no {}".format(cmd)
254 config_data.append(cmd)
255
256 if config_data:
257 if dut not in config_data_dict:
258 config_data_dict[dut] = config_data
259 else:
260 config_data_dict[dut].extend(config_data)
e8cd26fd 261
262
263def create_igmp_config(tgen, topo, input_dict=None, build=False):
264 """
265 API to configure igmp on router
266
267 Parameters
268 ----------
269 * `tgen` : Topogen object
270 * `topo` : json file data
271 * `input_dict` : Input dict data, required when configuring from
272 testcase
273 * `build` : Only for initial setup phase this is set as True.
274
275 Usage
276 -----
277 input_dict = {
278 "r1": {
279 "igmp": {
280 "interfaces": {
281 "r1-r0-eth0" :{
282 "igmp":{
283 "version": "2",
284 "delete": True
285 "query": {
286 "query-interval" : 100,
287 "query-max-response-time": 200
288 }
289 }
290 }
291 }
292 }
293 }
294 }
295
296 Returns
297 -------
298 True or False
299 """
300 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
301 result = False
302 if not input_dict:
303 input_dict = deepcopy(topo)
304 else:
305 topo = topo["routers"]
306 input_dict = deepcopy(input_dict)
4f99894d
CH
307
308 config_data_dict = {}
309
e8cd26fd 310 for router in input_dict.keys():
311 if "igmp" not in input_dict[router]:
312 logger.debug("Router %s: 'igmp' is not present in " "input_dict", router)
313 continue
314
315 igmp_data = input_dict[router]["igmp"]
316
317 if "interfaces" in igmp_data:
318 config_data = []
319 intf_data = igmp_data["interfaces"]
320
321 for intf_name in intf_data.keys():
322 cmd = "interface {}".format(intf_name)
323 config_data.append(cmd)
324 protocol = "igmp"
325 del_action = intf_data[intf_name]["igmp"].setdefault("delete", False)
58cfbb27 326 del_attr = intf_data[intf_name]["igmp"].setdefault("delete_attr", False)
e8cd26fd 327 cmd = "ip igmp"
328 if del_action:
329 cmd = "no {}".format(cmd)
58cfbb27
KK
330 if not del_attr:
331 config_data.append(cmd)
e8cd26fd 332
e8cd26fd 333 for attribute, data in intf_data[intf_name]["igmp"].items():
334 if attribute == "version":
335 cmd = "ip {} {} {}".format(protocol, attribute, data)
336 if del_action:
337 cmd = "no {}".format(cmd)
58cfbb27
KK
338 if not del_attr:
339 config_data.append(cmd)
e8cd26fd 340
341 if attribute == "join":
342 for group in data:
343 cmd = "ip {} {} {}".format(protocol, attribute, group)
344 if del_attr:
345 cmd = "no {}".format(cmd)
346 config_data.append(cmd)
347
348 if attribute == "query":
349 for query, value in data.items():
350 if query != "delete":
351 cmd = "ip {} {} {}".format(protocol, query, value)
352
353 if "delete" in intf_data[intf_name][protocol]["query"]:
354 cmd = "no {}".format(cmd)
355
356 config_data.append(cmd)
4f99894d
CH
357 if config_data:
358 config_data_dict[router] = config_data
e8cd26fd 359
4f99894d
CH
360 try:
361 result = create_common_configurations(
362 tgen, config_data_dict, "interface_config", build=build
363 )
364 except InvalidCLIError:
365 logger.error("create_igmp_config", exc_info=True)
366 result = False
e8cd26fd 367
368 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
369 return result
370
371
e13f9c4f
KK
372def create_mld_config(tgen, topo, input_dict=None, build=False):
373 """
d7032129 374 API to configure mld for pim6 on router
e13f9c4f
KK
375
376 Parameters
377 ----------
378 * `tgen` : Topogen object
379 * `topo` : json file data
380 * `input_dict` : Input dict data, required when configuring from
381 testcase
382 * `build` : Only for initial setup phase this is set as True.
383
384 Usage
385 -----
386 input_dict = {
387 "r1": {
388 "mld": {
389 "interfaces": {
390 "r1-r0-eth0" :{
391 "mld":{
392 "version": "2",
393 "delete": True
394 "query": {
395 "query-interval" : 100,
396 "query-max-response-time": 200
397 }
398 }
399 }
400 }
401 }
402 }
403 }
404
405 Returns
406 -------
407 True or False
408 """
409 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
410 result = False
411 if not input_dict:
412 input_dict = deepcopy(topo)
413 else:
414 topo = topo["routers"]
415 input_dict = deepcopy(input_dict)
416 for router in input_dict.keys():
417 if "mld" not in input_dict[router]:
418 logger.debug("Router %s: 'mld' is not present in " "input_dict", router)
419 continue
420
421 mld_data = input_dict[router]["mld"]
422
423 if "interfaces" in mld_data:
424 config_data = []
425 intf_data = mld_data["interfaces"]
426
427 for intf_name in intf_data.keys():
428 cmd = "interface {}".format(intf_name)
429 config_data.append(cmd)
430 protocol = "mld"
431 del_action = intf_data[intf_name]["mld"].setdefault("delete", False)
432 cmd = "ipv6 mld"
433 if del_action:
434 cmd = "no {}".format(cmd)
435 config_data.append(cmd)
436
437 del_attr = intf_data[intf_name]["mld"].setdefault("delete_attr", False)
438 join = intf_data[intf_name]["mld"].setdefault("join", None)
439 source = intf_data[intf_name]["mld"].setdefault("source", None)
440 version = intf_data[intf_name]["mld"].setdefault("version", False)
441 query = intf_data[intf_name]["mld"].setdefault("query", {})
442
443 if version:
444 cmd = "ipv6 {} version {}".format(protocol, version)
445 if del_action:
446 cmd = "no {}".format(cmd)
447 config_data.append(cmd)
448
449 if source and join:
450 for group in join:
451 cmd = "ipv6 {} join {} {}".format(protocol, group, source)
452
453 if del_attr:
454 cmd = "no {}".format(cmd)
455 config_data.append(cmd)
456
457 elif join:
458 for group in join:
459 cmd = "ipv6 {} join {}".format(protocol, group)
460
461 if del_attr:
462 cmd = "no {}".format(cmd)
463 config_data.append(cmd)
464
465 if query:
466 for _query, value in query.items():
467 if _query != "delete":
468 cmd = "ipv6 {} {} {}".format(protocol, _query, value)
469
470 if "delete" in intf_data[intf_name][protocol]["query"]:
471 cmd = "no {}".format(cmd)
472
473 config_data.append(cmd)
474 try:
475 result = create_common_configuration(
476 tgen, router, config_data, "interface_config", build=build
477 )
478 except InvalidCLIError:
479 errormsg = traceback.format_exc()
480 logger.error(errormsg)
481 return errormsg
482
483 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
484 return result
485
486
4f99894d 487def _enable_disable_pim_config(tgen, topo, input_dict, router, build=False):
e8cd26fd 488 """
489 Helper API to enable or disable pim on interfaces
490
491 Parameters
492 ----------
493 * `tgen` : Topogen object
494 * `topo` : json file data
495 * `input_dict` : Input dict data, required when configuring from testcase
496 * `router` : router id to be configured.
497 * `build` : Only for initial setup phase this is set as True.
498
499 Returns
500 -------
4f99894d 501 list of config
e8cd26fd 502 """
e8cd26fd 503
4f99894d 504 config_data = []
e8cd26fd 505
e13f9c4f 506 # Enable pim/pim6 on interfaces
4f99894d
CH
507 for destRouterLink, data in sorted(topo[router]["links"].items()):
508 if "pim" in data and data["pim"] == "enable":
509 # Loopback interfaces
510 if "type" in data and data["type"] == "loopback":
511 interface_name = destRouterLink
512 else:
513 interface_name = data["interface"]
514
515 cmd = "interface {}".format(interface_name)
516 config_data.append(cmd)
517 config_data.append("ip pim")
518
d7032129
KK
519 if "pim" in input_dict[router]:
520 if "disable" in input_dict[router]["pim"]:
521 enable_flag = False
522 interfaces = input_dict[router]["pim"]["disable"]
523
524 if type(interfaces) is not list:
525 interfaces = [interfaces]
526
527 for interface in interfaces:
528 cmd = "interface {}".format(interface)
529 config_data.append(cmd)
530 config_data.append("no ip pim")
531
e13f9c4f
KK
532 if "pim6" in data and data["pim6"] == "enable":
533 # Loopback interfaces
534 if "type" in data and data["type"] == "loopback":
535 interface_name = destRouterLink
536 else:
537 interface_name = data["interface"]
538
539 cmd = "interface {}".format(interface_name)
540 config_data.append(cmd)
541 config_data.append("ipv6 pim")
542
d7032129
KK
543 if "pim6" in input_dict[router]:
544 if "disable" in input_dict[router]["pim6"]:
545 enable_flag = False
546 interfaces = input_dict[router]["pim6"]["disable"]
547
548 if type(interfaces) is not list:
549 interfaces = [interfaces]
550
551 for interface in interfaces:
552 cmd = "interface {}".format(interface)
553 config_data.append(cmd)
554 config_data.append("no ipv6 pim")
555
4f99894d
CH
556 # pim global config
557 if "pim" in input_dict[router]:
558 pim_data = input_dict[router]["pim"]
559 del_action = pim_data.setdefault("delete", False)
560 for t in [
a53c08bc
CH
561 "join-prune-interval",
562 "keep-alive-timer",
563 "register-suppress-time",
4f99894d
CH
564 ]:
565 if t in pim_data:
566 cmd = "ip pim {} {}".format(t, pim_data[t])
567 if del_action:
568 cmd = "no {}".format(cmd)
0a76e764 569 config_data.append(cmd)
e8cd26fd 570
e13f9c4f
KK
571 # pim6 global config
572 if "pim6" in input_dict[router]:
573 pim6_data = input_dict[router]["pim6"]
574 del_action = pim6_data.setdefault("delete", False)
575 for t in [
576 "join-prune-interval",
577 "keep-alive-timer",
578 "register-suppress-time",
579 ]:
580 if t in pim6_data:
581 cmd = "ipv6 pim {} {}".format(t, pim6_data[t])
582 if del_action:
583 cmd = "no {}".format(cmd)
584 config_data.append(cmd)
585
4f99894d 586 return config_data
e8cd26fd 587
588
e8cd26fd 589def find_rp_details(tgen, topo):
590 """
591 Find who is RP in topology and returns list of RPs
592
593 Parameters:
594 -----------
595 * `tgen` : Topogen object
596 * `topo` : json file data
597
598 returns:
599 --------
600 errormsg or True
601 """
602
603 rp_details = {}
604
605 router_list = tgen.routers()
606 topo_data = topo["routers"]
607
608 for router in router_list.keys():
609
610 if "pim" not in topo_data[router]:
611 continue
612
613 pim_data = topo_data[router]["pim"]
614 if "rp" in pim_data:
615 rp_data = pim_data["rp"]
616 for rp_dict in rp_data:
617 # ip address of RP
618 rp_addr = rp_dict["rp_addr"]
619
620 for link, data in topo["routers"][router]["links"].items():
621 if data["ipv4"].split("/")[0] == rp_addr:
622 rp_details[router] = rp_addr
623
624 return rp_details
625
626
627def configure_pim_force_expire(tgen, topo, input_dict, build=False):
628 """
629 Helper API to create pim configuration.
630
631 Parameters
632 ----------
633 * `tgen` : Topogen object
634 * `topo` : json file data
635 * `input_dict` : Input dict data, required when configuring from testcase
636 * `build` : Only for initial setup phase this is set as True.
637
638 Usage
639 -----
640 input_dict ={
641 "l1": {
642 "pim": {
643 "force_expire":{
644 "10.0.10.1": ["255.1.1.1"]
645 }
646 }
647 }
648 }
649
650 result = create_pim_config(tgen, topo, input_dict)
651
652 Returns
653 -------
654 True or False
655 """
656
657 result = False
658 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4f99894d 659
e8cd26fd 660 try:
4f99894d 661 config_data_dict = {}
e8cd26fd 662
663 for dut in input_dict.keys():
664 if "pim" not in input_dict[dut]:
665 continue
666
667 pim_data = input_dict[dut]["pim"]
668
4f99894d 669 config_data = []
e8cd26fd 670 if "force_expire" in pim_data:
e8cd26fd 671 force_expire_data = pim_data["force_expire"]
672
673 for source, groups in force_expire_data.items():
674 if type(groups) is not list:
675 groups = [groups]
676
677 for group in groups:
678 cmd = "ip pim force-expire source {} group {}".format(
679 source, group
680 )
681 config_data.append(cmd)
682
4f99894d
CH
683 if config_data:
684 config_data_dict[dut] = config_data
e8cd26fd 685
4f99894d
CH
686 result = create_common_configurations(
687 tgen, config_data_dict, "pim", build=build
688 )
e8cd26fd 689 except InvalidCLIError:
4f99894d
CH
690 logger.error("configure_pim_force_expire", exc_info=True)
691 result = False
e8cd26fd 692
693 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
694 return result
695
696
697#############################################
698# Verification APIs
699#############################################
ed776e38 700@retry(retry_timeout=12)
3c41ebf8 701def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None, expected=True):
e8cd26fd 702 """
703 Verify all PIM neighbors are up and running, config is verified
704 using "show ip pim neighbor" cli
705
706 Parameters
707 ----------
708 * `tgen`: topogen object
709 * `topo` : json file data
710 * `dut` : dut info
711 * `iface` : link for which PIM nbr need to check
eab72dc8 712 * `nbr_ip` : neighbor ip of interface
3c41ebf8 713 * `expected` : expected results from API, by-default True
e8cd26fd 714
715 Usage
716 -----
eab72dc8 717 result = verify_pim_neighbors(tgen, topo, dut, iface=ens192, nbr_ip=20.1.1.2)
e8cd26fd 718
719 Returns
720 -------
721 errormsg(str) or True
722 """
723
724 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
725
726 for router in tgen.routers():
727 if dut is not None and dut != router:
728 continue
729
730 rnode = tgen.routers()[router]
731 show_ip_pim_neighbor_json = rnode.vtysh_cmd(
732 "show ip pim neighbor json", isjson=True
733 )
734
735 for destLink, data in topo["routers"][router]["links"].items():
736 if iface is not None and iface != data["interface"]:
737 continue
738
739 if "type" in data and data["type"] == "loopback":
740 continue
741
742 if "pim" not in data:
743 continue
744
697ce62f
KK
745 if "pim" in data and data["pim"] == "disable":
746 continue
747
e8cd26fd 748 if "pim" in data and data["pim"] == "enable":
749 local_interface = data["interface"]
750
751 if "-" in destLink:
752 # Spliting and storing destRouterLink data in tempList
753 tempList = destLink.split("-")
754
755 # destRouter
756 destLink = tempList.pop(0)
757
758 # Current Router Link
759 tempList.insert(0, router)
760 curRouter = "-".join(tempList)
761 else:
762 curRouter = router
763 if destLink not in topo["routers"]:
764 continue
765 data = topo["routers"][destLink]["links"][curRouter]
766 if "type" in data and data["type"] == "loopback":
767 continue
768
769 if "pim" not in data:
770 continue
771
772 logger.info("[DUT: %s]: Verifying PIM neighbor status:", router)
773
774 if "pim" in data and data["pim"] == "enable":
775 pim_nh_intf_ip = data["ipv4"].split("/")[0]
776
777 # Verifying PIM neighbor
778 if local_interface in show_ip_pim_neighbor_json:
779 if show_ip_pim_neighbor_json[local_interface]:
780 if (
781 show_ip_pim_neighbor_json[local_interface][pim_nh_intf_ip][
782 "neighbor"
783 ]
784 != pim_nh_intf_ip
785 ):
786 errormsg = (
787 "[DUT %s]: Local interface: %s, PIM"
788 " neighbor check failed "
789 "Expected neighbor: %s, Found neighbor:"
790 " %s"
791 % (
792 router,
793 local_interface,
794 pim_nh_intf_ip,
795 show_ip_pim_neighbor_json[local_interface][
796 pim_nh_intf_ip
797 ]["neighbor"],
798 )
799 )
800 return errormsg
801
802 logger.info(
803 "[DUT %s]: Local interface: %s, Found"
804 " expected PIM neighbor %s",
805 router,
806 local_interface,
807 pim_nh_intf_ip,
808 )
809 else:
810 errormsg = (
811 "[DUT %s]: Local interface: %s, and"
812 "interface ip: %s is not found in "
813 "PIM neighbor " % (router, local_interface, pim_nh_intf_ip)
814 )
815 return errormsg
816 else:
817 errormsg = (
818 "[DUT %s]: Local interface: %s, is not "
819 "present in PIM neighbor " % (router, local_interface)
820 )
821 return errormsg
822
823 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
824 return True
825
826
d7032129
KK
827@retry(retry_timeout=12)
828def verify_pim6_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None, expected=True):
829 """
830 Verify all pim6 neighbors are up and running, config is verified
831 using "show ipv6 pim neighbor" cli
832
833 Parameters
834 ----------
835 * `tgen`: topogen object
836 * `topo` : json file data
837 * `dut` : dut info
838 * `iface` : link for which PIM nbr need to check
839 * `nbr_ip` : neighbor ip of interface
840 * `expected` : expected results from API, by-default True
841
842 Usage
843 -----
844 result = verify_pim6_neighbors(tgen, topo, dut, iface=ens192, nbr_ip=20.1.1.2)
845
846 Returns
847 -------
848 errormsg(str) or True
849 """
850
851 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
852
853 for router in tgen.routers():
854 if dut is not None and dut != router:
855 continue
856
857 rnode = tgen.routers()[router]
858 show_ip_pim_neighbor_json = rnode.vtysh_cmd(
859 "show ipv6 pim neighbor json", isjson=True
860 )
861
862 for destLink, data in topo["routers"][router]["links"].items():
863 if "type" in data and data["type"] == "loopback":
864 continue
865
866 if iface is not None and iface != data["interface"]:
867 continue
868
869 if "pim6" not in data:
870 continue
871
872 if "pim6" in data and data["pim6"] == "disable":
873 continue
874
875 if "pim6" in data and data["pim6"] == "enable":
876 local_interface = data["interface"]
877
878 if "-" in destLink:
879 # Spliting and storing destRouterLink data in tempList
880 tempList = destLink.split("-")
881
882 # destRouter
883 destLink = tempList.pop(0)
884
885 # Current Router Link
886 tempList.insert(0, router)
887 curRouter = "-".join(tempList)
888 else:
889 curRouter = router
890 if destLink not in topo["routers"]:
891 continue
892 data = topo["routers"][destLink]["links"][curRouter]
893 peer_interface = data["interface"]
894 if "type" in data and data["type"] == "loopback":
895 continue
896
897 if "pim6" not in data:
898 continue
899
900 logger.info("[DUT: %s]: Verifying PIM neighbor status:", router)
901
902 if "pim6" in data and data["pim6"] == "enable":
903 pim_nh_intf_ip = get_frr_ipv6_linklocal(tgen, destLink, peer_interface)
904
905 # Verifying PIM neighbor
906 if local_interface in show_ip_pim_neighbor_json:
907 if show_ip_pim_neighbor_json[local_interface]:
908 if (
909 show_ip_pim_neighbor_json[local_interface][pim_nh_intf_ip][
910 "neighbor"
911 ]
912 != pim_nh_intf_ip
913 ):
914 errormsg = (
915 "[DUT %s]: Local interface: %s, PIM6"
916 " neighbor check failed "
917 "Expected neighbor: %s, Found neighbor:"
918 " %s"
919 % (
920 router,
921 local_interface,
922 pim_nh_intf_ip,
923 show_ip_pim_neighbor_json[local_interface][
924 pim_nh_intf_ip
925 ]["neighbor"],
926 )
927 )
928 return errormsg
929
930 logger.info(
931 "[DUT %s]: Local interface: %s, Found"
932 " expected PIM6 neighbor %s",
933 router,
934 local_interface,
935 pim_nh_intf_ip,
936 )
937 else:
938 errormsg = (
939 "[DUT %s]: Local interface: %s, and"
940 "interface ip: %s is not found in "
941 "PIM6 neighbor " % (router, local_interface, pim_nh_intf_ip)
942 )
943 return errormsg
944 else:
945 errormsg = (
946 "[DUT %s]: Local interface: %s, is not "
947 "present in PIM6 neighbor " % (router, local_interface)
948 )
949 return errormsg
950
951 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
952 return True
953
954
de3d6b4d 955@retry(retry_timeout=40, diag_pct=0)
3c41ebf8 956def verify_igmp_groups(tgen, dut, interface, group_addresses, expected=True):
e8cd26fd 957 """
958 Verify IGMP groups are received from an intended interface
959 by running "show ip igmp groups" command
960
961 Parameters
962 ----------
963 * `tgen`: topogen object
964 * `dut`: device under test
965 * `interface`: interface, from which IGMP groups would be received
966 * `group_addresses`: IGMP group address
3c41ebf8 967 * `expected` : expected results from API, by-default True
e8cd26fd 968
969 Usage
970 -----
971 dut = "r1"
972 interface = "r1-r0-eth0"
973 group_address = "225.1.1.1"
974 result = verify_igmp_groups(tgen, dut, interface, group_address)
975
976 Returns
977 -------
978 errormsg(str) or True
979 """
980
981 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
982
983 if dut not in tgen.routers():
984 return False
985
986 rnode = tgen.routers()[dut]
987
988 logger.info("[DUT: %s]: Verifying IGMP groups received:", dut)
989 show_ip_igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
990
991 if type(group_addresses) is not list:
992 group_addresses = [group_addresses]
993
994 if interface in show_ip_igmp_json:
995 show_ip_igmp_json = show_ip_igmp_json[interface]["groups"]
996 else:
997 errormsg = (
998 "[DUT %s]: Verifying IGMP group received"
999 " from interface %s [FAILED]!! " % (dut, interface)
1000 )
1001 return errormsg
1002
1003 found = False
1004 for grp_addr in group_addresses:
1005 for index in show_ip_igmp_json:
1006 if index["group"] == grp_addr:
1007 found = True
1008 break
1009 if found is not True:
1010 errormsg = (
1011 "[DUT %s]: Verifying IGMP group received"
1012 " from interface %s [FAILED]!! "
1013 " Expected not found: %s" % (dut, interface, grp_addr)
1014 )
1015 return errormsg
1016
1017 logger.info(
1018 "[DUT %s]: Verifying IGMP group %s received "
1019 "from interface %s [PASSED]!! ",
1020 dut,
1021 grp_addr,
1022 interface,
1023 )
1024
1025 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1026 return True
1027
1028
d7032129 1029@retry(retry_timeout=60, diag_pct=2)
e8cd26fd 1030def verify_upstream_iif(
a53c08bc
CH
1031 tgen,
1032 dut,
1033 iif,
1034 src_address,
1035 group_addresses,
1036 joinState=None,
d7032129 1037 regState=None,
a53c08bc 1038 refCount=1,
d7032129 1039 addr_type="ipv4",
a53c08bc 1040 expected=True,
e8cd26fd 1041):
1042 """
1043 Verify upstream inbound interface is updated correctly
1044 by running "show ip pim upstream" cli
1045
1046 Parameters
1047 ----------
1048 * `tgen`: topogen object
1049 * `dut`: device under test
1050 * `iif`: inbound interface
1051 * `src_address`: source address
1052 * `group_addresses`: IGMP group address
1053 * `joinState`: upstream join state
1054 * `refCount`: refCount value
3c41ebf8 1055 * `expected` : expected results from API, by-default True
e8cd26fd 1056
1057 Usage
1058 -----
1059 dut = "r1"
1060 iif = "r1-r0-eth0"
1061 src_address = "*"
1062 group_address = "225.1.1.1"
1063 result = verify_upstream_iif(tgen, dut, iif, src_address, group_address,
1064 state, refCount)
1065
1066 Returns
1067 -------
1068 errormsg(str) or True
1069 """
e8cd26fd 1070 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1071
1072 if dut not in tgen.routers():
1073 return False
1074
1075 rnode = tgen.routers()[dut]
1076
1077 logger.info(
d7032129
KK
1078 "[DUT: %s]: Verifying upstream Inbound Interface"
1079 " for IGMP/MLD groups received:",
e8cd26fd 1080 dut,
1081 )
e8cd26fd 1082
1083 if type(group_addresses) is not list:
1084 group_addresses = [group_addresses]
1085
1086 if type(iif) is not list:
1087 iif = [iif]
1088
e13f9c4f
KK
1089 for grp in group_addresses:
1090 addr_type = validate_ip_address(grp)
1091
1092 if addr_type == "ipv4":
1093 ip_cmd = "ip"
1094 elif addr_type == "ipv6":
1095 ip_cmd = "ipv6"
1096
1097 cmd = "show {} pim upstream json".format(ip_cmd)
1098 show_ip_pim_upstream_json = run_frr_cmd(rnode, cmd, isjson=True)
1099
e8cd26fd 1100 for grp_addr in group_addresses:
1101 # Verify group address
1102 if grp_addr not in show_ip_pim_upstream_json:
1103 errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
1104 dut,
1105 grp_addr,
1106 )
1107 return errormsg
1108 group_addr_json = show_ip_pim_upstream_json[grp_addr]
1109
1110 # Verify source address
1111 if src_address not in group_addr_json:
1112 errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
1113 dut,
1114 src_address,
1115 grp_addr,
1116 )
1117 return errormsg
1118
1119 # Verify Inbound Interface
1120 found = False
1121 for in_interface in iif:
1122 if group_addr_json[src_address]["inboundInterface"] == in_interface:
1123 if refCount > 0:
1124 logger.info(
1125 "[DUT %s]: Verifying refCount "
1126 "for (%s,%s) [PASSED]!! "
1127 " Found Expected: %s",
1128 dut,
1129 src_address,
1130 grp_addr,
1131 group_addr_json[src_address]["refCount"],
1132 )
1133 found = True
1134 if found:
1135 if joinState is None:
1136 if group_addr_json[src_address]["joinState"] != "Joined":
1137 errormsg = (
1138 "[DUT %s]: Verifying iif "
db726bb8
KK
1139 "(Inbound Interface) and joinState "
1140 "for (%s, %s), Expected iif: %s, "
1141 "Found iif : %s, and Expected "
1142 "joinState :%s , Found joinState: %s"
e8cd26fd 1143 % (
1144 dut,
1145 src_address,
1146 grp_addr,
e8cd26fd 1147 in_interface,
1148 group_addr_json[src_address]["inboundInterface"],
db726bb8 1149 joinState,
244f2df0 1150 group_addr_json[src_address]["joinState"],
e8cd26fd 1151 )
1152 )
1153 return errormsg
1154
1155 elif group_addr_json[src_address]["joinState"] != joinState:
1156 errormsg = (
1157 "[DUT %s]: Verifying iif "
db726bb8
KK
1158 "(Inbound Interface) and joinState "
1159 "for (%s, %s), Expected iif: %s, "
1160 "Found iif : %s, and Expected "
1161 "joinState :%s , Found joinState: %s"
e8cd26fd 1162 % (
1163 dut,
1164 src_address,
1165 grp_addr,
e8cd26fd 1166 in_interface,
1167 group_addr_json[src_address]["inboundInterface"],
db726bb8 1168 joinState,
244f2df0 1169 group_addr_json[src_address]["joinState"],
e8cd26fd 1170 )
1171 )
1172 return errormsg
1173
d7032129
KK
1174 if regState:
1175 if group_addr_json[src_address]["regState"] != regState:
1176 errormsg = (
1177 "[DUT %s]: Verifying iif "
db726bb8
KK
1178 "(Inbound Interface) and regState "
1179 "for (%s, %s), Expected iif: %s, "
1180 "Found iif : %s, and Expected "
1181 "regState :%s , Found regState: %s"
d7032129
KK
1182 % (
1183 dut,
1184 src_address,
1185 grp_addr,
d7032129
KK
1186 in_interface,
1187 group_addr_json[src_address]["inboundInterface"],
db726bb8 1188 regState,
244f2df0 1189 group_addr_json[src_address]["regState"],
d7032129
KK
1190 )
1191 )
1192 return errormsg
1193
e8cd26fd 1194 logger.info(
1195 "[DUT %s]: Verifying iif(Inbound Interface)"
d7032129 1196 " for (%s,%s) and joinState is %s regstate is %s [PASSED]!! "
e8cd26fd 1197 " Found Expected: (%s)",
1198 dut,
1199 src_address,
1200 grp_addr,
1201 group_addr_json[src_address]["joinState"],
d7032129 1202 group_addr_json[src_address]["regState"],
e8cd26fd 1203 group_addr_json[src_address]["inboundInterface"],
1204 )
1205 if not found:
1206 errormsg = (
1207 "[DUT %s]: Verifying iif "
1208 "(Inbound Interface) for (%s, %s) "
1209 "[FAILED]!! "
1210 " Expected: %s, Found: %s"
1211 % (
1212 dut,
1213 src_address,
1214 grp_addr,
1215 in_interface,
1216 group_addr_json[src_address]["inboundInterface"],
1217 )
1218 )
1219 return errormsg
1220
25837461
KK
1221 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1222 return True
e8cd26fd 1223
1224
ed776e38 1225@retry(retry_timeout=12)
a53c08bc 1226def verify_join_state_and_timer(
d7032129 1227 tgen, dut, iif, src_address, group_addresses, addr_type="ipv4", expected=True
a53c08bc 1228):
e8cd26fd 1229 """
1230 Verify join state is updated correctly and join timer is
1231 running with the help of "show ip pim upstream" cli
1232
1233 Parameters
1234 ----------
1235 * `tgen`: topogen object
1236 * `dut`: device under test
1237 * `iif`: inbound interface
1238 * `src_address`: source address
1239 * `group_addresses`: IGMP group address
3c41ebf8 1240 * `expected` : expected results from API, by-default True
e8cd26fd 1241
1242 Usage
1243 -----
1244 dut = "r1"
1245 iif = "r1-r0-eth0"
1246 group_address = "225.1.1.1"
1247 result = verify_join_state_and_timer(tgen, dut, iif, group_address)
1248
1249 Returns
1250 -------
1251 errormsg(str) or True
1252 """
1253
1254 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1255 errormsg = ""
1256
1257 if dut not in tgen.routers():
1258 return False
1259
1260 rnode = tgen.routers()[dut]
1261
1262 logger.info(
1263 "[DUT: %s]: Verifying Join state and Join Timer" " for IGMP groups received:",
1264 dut,
1265 )
e8cd26fd 1266
1267 if type(group_addresses) is not list:
1268 group_addresses = [group_addresses]
1269
e13f9c4f
KK
1270 for grp in group_addresses:
1271 addr_type = validate_ip_address(grp)
1272
1273 if addr_type == "ipv4":
1274 cmd = "show ip pim upstream json"
1275 elif addr_type == "ipv6":
1276 cmd = "show ipv6 pim upstream json"
1277 show_ip_pim_upstream_json = run_frr_cmd(rnode, cmd, isjson=True)
1278
e8cd26fd 1279 for grp_addr in group_addresses:
1280 # Verify group address
1281 if grp_addr not in show_ip_pim_upstream_json:
1282 errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
1283 dut,
1284 grp_addr,
1285 )
1286 return errormsg
1287
1288 group_addr_json = show_ip_pim_upstream_json[grp_addr]
1289
1290 # Verify source address
1291 if src_address not in group_addr_json:
1292 errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
1293 dut,
1294 src_address,
1295 grp_addr,
1296 )
1297 return errormsg
1298
1299 # Verify join state
1300 joinState = group_addr_json[src_address]["joinState"]
1301 if joinState != "Joined":
1302 error = (
1303 "[DUT %s]: Verifying join state for"
1304 " (%s,%s) [FAILED]!! "
1305 " Expected: %s, Found: %s"
1306 % (dut, src_address, grp_addr, "Joined", joinState)
1307 )
1308 errormsg = errormsg + "\n" + str(error)
1309 else:
1310 logger.info(
1311 "[DUT %s]: Verifying join state for"
1312 " (%s,%s) [PASSED]!! "
1313 " Found Expected: %s",
1314 dut,
1315 src_address,
1316 grp_addr,
1317 joinState,
1318 )
1319
1320 # Verify join timer
1321 joinTimer = group_addr_json[src_address]["joinTimer"]
1322 if not re.match(r"(\d{2}):(\d{2}):(\d{2})", joinTimer):
1323 error = (
1324 "[DUT %s]: Verifying join timer for"
1325 " (%s,%s) [FAILED]!! "
49581587
CH
1326 " Expected: %s, Found: %s"
1327 ) % (
e8cd26fd 1328 dut,
1329 src_address,
1330 grp_addr,
1331 "join timer should be running",
1332 joinTimer,
1333 )
1334 errormsg = errormsg + "\n" + str(error)
1335 else:
1336 logger.info(
1337 "[DUT %s]: Verifying join timer is running"
1338 " for (%s,%s) [PASSED]!! "
1339 " Found Expected: %s",
1340 dut,
1341 src_address,
1342 grp_addr,
1343 joinTimer,
1344 )
1345
1346 if errormsg != "":
1347 return errormsg
1348
1349 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1350 return True
1351
1352
de3d6b4d 1353@retry(retry_timeout=120, diag_pct=0)
4fafd29f 1354def verify_mroutes(
a53c08bc
CH
1355 tgen,
1356 dut,
1357 src_address,
1358 group_addresses,
1359 iif,
1360 oil,
1361 return_uptime=False,
1362 mwait=0,
d7032129 1363 addr_type="ipv4",
a53c08bc 1364 expected=True,
e8cd26fd 1365):
1366 """
1367 Verify ip mroutes and make sure (*, G)/(S, G) is present in mroutes
4fafd29f 1368 by running "show ip/ipv6 mroute" cli
e8cd26fd 1369
1370 Parameters
1371 ----------
1372 * `tgen`: topogen object
1373 * `dut`: device under test
1374 * `src_address`: source address
1375 * `group_addresses`: IGMP group address
1376 * `iif`: Incoming interface
1377 * `oil`: Outgoing interface
1378 * `return_uptime`: If True, return uptime dict, default is False
1379 * `mwait`: Wait time, default is 0
3c41ebf8 1380 * `expected` : expected results from API, by-default True
e8cd26fd 1381
1382 Usage
1383 -----
1384 dut = "r1"
1385 group_address = "225.1.1.1"
4fafd29f 1386 result = verify_mroutes(tgen, dut, src_address, group_address)
e8cd26fd 1387
1388 Returns
1389 -------
1390 errormsg(str) or True
1391 """
1392
1393 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1394
1395 if dut not in tgen.routers():
1396 return False
1397
1398 rnode = tgen.routers()[dut]
1399
e13f9c4f
KK
1400 if not isinstance(group_addresses, list):
1401 group_addresses = [group_addresses]
1402
1403 if not isinstance(iif, list) and iif != "none":
1404 iif = [iif]
1405
1406 if not isinstance(oil, list) and oil != "none":
1407 oil = [oil]
1408
1409 for grp in group_addresses:
1410 addr_type = validate_ip_address(grp)
1411
1412 if addr_type == "ipv4":
1413 ip_cmd = "ip"
1414 elif addr_type == "ipv6":
1415 ip_cmd = "ipv6"
1416
e8cd26fd 1417 if return_uptime:
1418 logger.info("Sleeping for %s sec..", mwait)
1419 sleep(mwait)
1420
1421 logger.info("[DUT: %s]: Verifying ip mroutes", dut)
e13f9c4f
KK
1422 show_ip_mroute_json = run_frr_cmd(
1423 rnode, "show {} mroute json".format(ip_cmd), isjson=True
1424 )
e8cd26fd 1425
1426 if return_uptime:
1427 uptime_dict = {}
1428
1429 if bool(show_ip_mroute_json) == False:
1430 error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
1431 return error_msg
1432
e8cd26fd 1433 for grp_addr in group_addresses:
1434 if grp_addr not in show_ip_mroute_json:
1435 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
1436 dut,
1437 src_address,
1438 grp_addr,
1439 )
1440 return errormsg
1441 else:
1442 if return_uptime:
1443 uptime_dict[grp_addr] = {}
1444
1445 group_addr_json = show_ip_mroute_json[grp_addr]
1446
1447 if src_address not in group_addr_json:
1448 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
1449 dut,
1450 src_address,
1451 grp_addr,
1452 )
1453 return errormsg
1454 else:
1455 if return_uptime:
1456 uptime_dict[grp_addr][src_address] = {}
1457
1458 mroutes = group_addr_json[src_address]
1459
1460 if mroutes["installed"] != 0:
1461 logger.info(
1462 "[DUT %s]: mroute (%s,%s) is installed", dut, src_address, grp_addr
1463 )
1464
1465 if "oil" not in mroutes:
1466 if oil == "none" and mroutes["iif"] in iif:
1467 logger.info(
1468 "[DUT %s]: Verifying (%s, %s) mroute,"
1469 " [PASSED]!! Found Expected: "
1470 "(iif: %s, oil: %s, installed: (%s,%s))",
1471 dut,
1472 src_address,
1473 grp_addr,
1474 mroutes["iif"],
1475 oil,
1476 src_address,
1477 grp_addr,
1478 )
1479 else:
1480 errormsg = (
1481 "[DUT %s]: Verifying (%s, %s) mroute,"
1482 " [FAILED]!! "
1483 "Expected: (oil: %s, installed:"
1484 " (%s,%s)) Found: ( oil: none, "
1485 "installed: (%s,%s))"
1486 % (
1487 dut,
1488 src_address,
1489 grp_addr,
1490 oil,
1491 src_address,
1492 grp_addr,
1493 src_address,
1494 grp_addr,
1495 )
1496 )
1497
1498 return errormsg
1499
1500 else:
1501 found = False
1502 for route, data in mroutes["oil"].items():
1503 if route in oil and route != "pimreg":
1504 if (
1505 data["source"] == src_address
1506 and data["group"] == grp_addr
1507 and data["inboundInterface"] in iif
1508 and data["outboundInterface"] in oil
1509 ):
1510 if return_uptime:
1511
1512 uptime_dict[grp_addr][src_address] = data["upTime"]
1513
1514 logger.info(
1515 "[DUT %s]: Verifying (%s, %s)"
1516 " mroute, [PASSED]!! "
1517 "Found Expected: "
1518 "(iif: %s, oil: %s, installed:"
1519 " (%s,%s)",
1520 dut,
1521 src_address,
1522 grp_addr,
1523 data["inboundInterface"],
1524 data["outboundInterface"],
1525 data["source"],
1526 data["group"],
1527 )
1528 found = True
1529 break
1530 else:
1531 continue
1532
1533 if not found:
1534 errormsg = (
1535 "[DUT %s]: Verifying (%s, %s)"
1536 " mroute [FAILED]!! "
1537 "Expected in: (iif: %s, oil: %s,"
1538 " installed: (%s,%s)) Found: "
1539 "(iif: %s, oil: %s, "
1540 "installed: (%s,%s))"
1541 % (
1542 dut,
1543 src_address,
1544 grp_addr,
1545 iif,
1546 oil,
1547 src_address,
1548 grp_addr,
1549 data["inboundInterface"],
1550 data["outboundInterface"],
1551 data["source"],
1552 data["group"],
1553 )
1554 )
1555 return errormsg
1556
1557 else:
1558 errormsg = "[DUT %s]: mroute (%s,%s) is not installed" % (
1559 dut,
1560 src_address,
1561 grp_addr,
1562 )
1563 return errormsg
1564
1565 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1566 return True if return_uptime == False else uptime_dict
1567
1568
de3d6b4d 1569@retry(retry_timeout=60, diag_pct=0)
e8cd26fd 1570def verify_pim_rp_info(
a53c08bc
CH
1571 tgen,
1572 topo,
1573 dut,
1574 group_addresses,
1575 oif=None,
1576 rp=None,
1577 source=None,
1578 iamrp=None,
d7032129 1579 addr_type="ipv4",
a53c08bc 1580 expected=True,
e8cd26fd 1581):
1582 """
1583 Verify pim rp info by running "show ip pim rp-info" cli
1584
1585 Parameters
1586 ----------
1587 * `tgen`: topogen object
1588 * `topo`: JSON file handler
1589 * `dut`: device under test
1590 * `group_addresses`: IGMP group address
1591 * `oif`: outbound interface name
1592 * `rp`: RP address
1593 * `source`: Source of RP
1594 * `iamrp`: User defined RP
3c41ebf8 1595 * `expected` : expected results from API, by-default True
e8cd26fd 1596
1597 Usage
1598 -----
1599 dut = "r1"
1600 result = verify_pim_rp_info(tgen, topo, dut, group_address,
1601 rp=rp, source="BSR")
1602
1603 Returns
1604 -------
1605 errormsg(str) or True
1606 """
1607
1608 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1609
1610 if dut not in tgen.routers():
1611 return False
1612
1613 rnode = tgen.routers()[dut]
1614
e8cd26fd 1615 if type(group_addresses) is not list:
1616 group_addresses = [group_addresses]
1617
1618 if type(oif) is not list:
1619 oif = [oif]
1620
e13f9c4f
KK
1621 for grp in group_addresses:
1622 addr_type = validate_ip_address(grp)
1623
1624 if addr_type == "ipv4":
1625 ip_cmd = "ip"
1626 elif addr_type == "ipv6":
1627 ip_cmd = "ipv6"
1628
e8cd26fd 1629 for grp_addr in group_addresses:
1630 if rp is None:
1631 rp_details = find_rp_details(tgen, topo)
1632
1633 if dut in rp_details:
1634 iamRP = True
1635 else:
1636 iamRP = False
1637 else:
e13f9c4f
KK
1638 if addr_type == "ipv4":
1639 show_ip_route_json = run_frr_cmd(
1640 rnode, "show ip route connected json", isjson=True
1641 )
1642 elif addr_type == "ipv6":
1643 show_ip_route_json = run_frr_cmd(
1644 rnode, "show ipv6 route connected json", isjson=True
1645 )
e8cd26fd 1646 for _rp in show_ip_route_json.keys():
1647 if rp == _rp.split("/")[0]:
1648 iamRP = True
1649 break
1650 else:
1651 iamRP = False
1652
e13f9c4f
KK
1653 logger.info("[DUT: %s]: Verifying ip rp info", dut)
1654 cmd = "show {} pim rp-info json".format(ip_cmd)
1655 show_ip_rp_info_json = run_frr_cmd(rnode, cmd, isjson=True)
1656
e8cd26fd 1657 if rp not in show_ip_rp_info_json:
e13f9c4f
KK
1658 errormsg = (
1659 "[DUT %s]: Verifying rp-info "
1660 "for rp_address %s [FAILED]!! " % (dut, rp)
e8cd26fd 1661 )
1662 return errormsg
1663 else:
1664 group_addr_json = show_ip_rp_info_json[rp]
1665
1666 for rp_json in group_addr_json:
e13f9c4f
KK
1667 if "rpAddress" not in rp_json:
1668 errormsg = "[DUT %s]: %s key not " "present in rp-info " % (
1669 dut,
1670 "rpAddress",
1671 )
1672 return errormsg
1673
e8cd26fd 1674 if oif is not None:
1675 found = False
1676 if rp_json["outboundInterface"] not in oif:
1677 errormsg = (
1678 "[DUT %s]: Verifying OIF "
1679 "for group %s and RP %s [FAILED]!! "
1680 "Expected interfaces: (%s),"
1681 " Found: (%s)"
1682 % (dut, grp_addr, rp, oif, rp_json["outboundInterface"])
1683 )
1684 return errormsg
1685
1686 logger.info(
1687 "[DUT %s]: Verifying OIF "
1688 "for group %s and RP %s [PASSED]!! "
1689 "Found Expected: (%s)"
1690 % (dut, grp_addr, rp, rp_json["outboundInterface"])
1691 )
1692
1693 if source is not None:
1694 if rp_json["source"] != source:
1695 errormsg = (
1696 "[DUT %s]: Verifying SOURCE "
1697 "for group %s and RP %s [FAILED]!! "
1698 "Expected: (%s),"
1699 " Found: (%s)" % (dut, grp_addr, rp, source, rp_json["source"])
1700 )
1701 return errormsg
1702
1703 logger.info(
1704 "[DUT %s]: Verifying SOURCE "
1705 "for group %s and RP %s [PASSED]!! "
1706 "Found Expected: (%s)" % (dut, grp_addr, rp, rp_json["source"])
1707 )
1708
1709 if rp_json["group"] == grp_addr and iamrp is not None:
1710 if iamRP:
1711 if rp_json["iAmRP"]:
1712 logger.info(
1713 "[DUT %s]: Verifying group "
1714 "and iAmRP [PASSED]!!"
1715 " Found Expected: (%s, %s:%s)",
1716 dut,
1717 grp_addr,
1718 "iAmRP",
1719 rp_json["iAmRP"],
1720 )
1721 else:
1722 errormsg = (
1723 "[DUT %s]: Verifying group"
1724 "%s and iAmRP [FAILED]!! "
1725 "Expected: (iAmRP: %s),"
1726 " Found: (iAmRP: %s)"
1727 % (dut, grp_addr, "true", rp_json["iAmRP"])
1728 )
1729 return errormsg
1730
1731 if not iamRP:
1732 if rp_json["iAmRP"] == False:
1733 logger.info(
1734 "[DUT %s]: Verifying group "
1735 "and iAmNotRP [PASSED]!!"
1736 " Found Expected: (%s, %s:%s)",
1737 dut,
1738 grp_addr,
1739 "iAmRP",
1740 rp_json["iAmRP"],
1741 )
1742 else:
1743 errormsg = (
1744 "[DUT %s]: Verifying group"
1745 "%s and iAmRP [FAILED]!! "
1746 "Expected: (iAmRP: %s),"
1747 " Found: (iAmRP: %s)"
1748 % (dut, grp_addr, "false", rp_json["iAmRP"])
1749 )
1750 return errormsg
1751
1752 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1753 return True
1754
1755
de3d6b4d 1756@retry(retry_timeout=60, diag_pct=0)
e8cd26fd 1757def verify_pim_state(
a53c08bc
CH
1758 tgen,
1759 dut,
1760 iif,
1761 oil,
1762 group_addresses,
1763 src_address=None,
1764 installed_fl=None,
d7032129 1765 addr_type="ipv4",
a53c08bc 1766 expected=True,
e8cd26fd 1767):
1768 """
1769 Verify pim state by running "show ip pim state" cli
1770
1771 Parameters
1772 ----------
1773 * `tgen`: topogen object
1774 * `dut`: device under test
1775 * `iif`: inbound interface
1776 * `oil`: outbound interface
1777 * `group_addresses`: IGMP group address
1778 * `src_address`: source address, default = None
1779 * installed_fl` : Installed flag
3c41ebf8 1780 * `expected` : expected results from API, by-default True
e8cd26fd 1781
1782 Usage
1783 -----
1784 dut = "r1"
1785 iif = "r1-r3-eth1"
1786 oil = "r1-r0-eth0"
1787 group_address = "225.1.1.1"
1788 result = verify_pim_state(tgen, dut, iif, oil, group_address)
1789
1790 Returns
1791 -------
1792 errormsg(str) or True
1793 """
1794
1795 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1796
1797 if dut not in tgen.routers():
1798 return False
1799
1800 rnode = tgen.routers()[dut]
1801
1802 logger.info("[DUT: %s]: Verifying pim state", dut)
e8cd26fd 1803
1804 if type(group_addresses) is not list:
1805 group_addresses = [group_addresses]
1806
e13f9c4f
KK
1807 for grp in group_addresses:
1808 addr_type = validate_ip_address(grp)
1809
1810 if addr_type == "ipv4":
1811 ip_cmd = "ip"
1812 elif addr_type == "ipv6":
1813 ip_cmd = "ipv6"
1814
1815 logger.info("[DUT: %s]: Verifying pim state", dut)
1816 show_pim_state_json = run_frr_cmd(
1817 rnode, "show {} pim state json".format(ip_cmd), isjson=True
1818 )
1819
1820 if installed_fl is None:
1821 installed_fl = 1
1822
e8cd26fd 1823 for grp_addr in group_addresses:
1824 if src_address is None:
1825 src_address = "*"
1826 pim_state_json = show_pim_state_json[grp_addr][src_address]
1827 else:
1828 pim_state_json = show_pim_state_json[grp_addr][src_address]
1829
f932966b 1830 if pim_state_json["installed"] == installed_fl:
e8cd26fd 1831 logger.info(
1832 "[DUT %s]: group %s is installed flag: %s",
1833 dut,
1834 grp_addr,
f932966b 1835 pim_state_json["installed"],
e8cd26fd 1836 )
1837 for interface, data in pim_state_json[iif].items():
1838 if interface != oil:
1839 continue
1840
1841 # Verify iif, oil and installed state
1842 if (
1843 data["group"] == grp_addr
1844 and data["installed"] == installed_fl
1845 and data["inboundInterface"] == iif
1846 and data["outboundInterface"] == oil
1847 ):
1848 logger.info(
1849 "[DUT %s]: Verifying pim state for group"
1850 " %s [PASSED]!! Found Expected: "
1851 "(iif: %s, oil: %s, installed: %s) ",
1852 dut,
1853 grp_addr,
1854 data["inboundInterface"],
1855 data["outboundInterface"],
1856 data["installed"],
1857 )
1858 else:
1859 errormsg = (
1860 "[DUT %s]: Verifying pim state for group"
1861 " %s, [FAILED]!! Expected: "
5aab262b
QY
1862 "(iif: %s, oil: %s, installed: %s) "
1863 % (dut, grp_addr, iif, oil, "1"),
e8cd26fd 1864 "Found: (iif: %s, oil: %s, installed: %s)"
1865 % (
e8cd26fd 1866 data["inboundInterface"],
1867 data["outboundInterface"],
1868 data["installed"],
1869 ),
1870 )
1871 return errormsg
1872 else:
1873 errormsg = "[DUT %s]: %s install flag value not as expected" % (
1874 dut,
1875 grp_addr,
1876 )
1877 return errormsg
1878
1879 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1880 return True
1881
1882
0b01a0bb 1883def get_pim_interface_traffic(tgen, input_dict):
e8cd26fd 1884 """
d7032129 1885 get ip pim interface traffic by running
e8cd26fd 1886 "show ip pim interface traffic" cli
1887
1888 Parameters
1889 ----------
1890 * `tgen`: topogen object
1891 * `input_dict(dict)`: defines DUT, what and from which interfaces
0b01a0bb 1892 traffic needs to be retrieved
e8cd26fd 1893 Usage
1894 -----
1895 input_dict = {
1896 "r1": {
1897 "r1-r0-eth0": {
1898 "helloRx": 0,
1899 "helloTx": 1,
1900 "joinRx": 0,
1901 "joinTx": 0
1902 }
1903 }
1904 }
1905
0b01a0bb 1906 result = get_pim_interface_traffic(tgen, input_dict)
e8cd26fd 1907
1908 Returns
1909 -------
1910 errormsg(str) or True
1911 """
1912
1913 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1914
1915 output_dict = {}
1916 for dut in input_dict.keys():
1917 if dut not in tgen.routers():
1918 continue
1919
1920 rnode = tgen.routers()[dut]
1921
1922 logger.info("[DUT: %s]: Verifying pim interface traffic", dut)
e8cd26fd 1923
3d7d6e9a
DS
1924 def show_pim_intf_traffic(rnode, dut, input_dict, output_dict):
1925 show_pim_intf_traffic_json = run_frr_cmd(
1926 rnode, "show ip pim interface traffic json", isjson=True
1927 )
e8cd26fd 1928
3d7d6e9a
DS
1929 output_dict[dut] = {}
1930 for intf, data in input_dict[dut].items():
1931 interface_json = show_pim_intf_traffic_json[intf]
1932 for state in data:
1933
1934 # Verify Tx/Rx
1935 if state in interface_json:
1936 output_dict[dut][state] = interface_json[state]
1937 else:
1938 errormsg = (
1939 "[DUT %s]: %s is not present"
1940 "for interface %s [FAILED]!! " % (dut, state, intf)
1941 )
1942 return errormsg
1943 return None
1944
1945 test_func = functools.partial(
1946 show_pim_intf_traffic, rnode, dut, input_dict, output_dict
1947 )
1948 (result, out) = topotest.run_and_expect(test_func, None, count=20, wait=1)
1949 if not result:
1950 return out
e8cd26fd 1951
1952 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1953 return output_dict
1954
1955
d7032129
KK
1956def get_pim6_interface_traffic(tgen, input_dict):
1957 """
1958 get ipv6 pim interface traffic by running
1959 "show ipv6 pim interface traffic" cli
1960
1961 Parameters
1962 ----------
1963 * `tgen`: topogen object
1964 * `input_dict(dict)`: defines DUT, what and from which interfaces
1965 traffic needs to be retrieved
1966 Usage
1967 -----
1968 input_dict = {
1969 "r1": {
1970 "r1-r0-eth0": {
1971 "helloRx": 0,
1972 "helloTx": 1,
1973 "joinRx": 0,
1974 "joinTx": 0
1975 }
1976 }
1977 }
1978
1979 result = get_pim_interface_traffic(tgen, input_dict)
1980
1981 Returns
1982 -------
1983 errormsg(str) or True
1984 """
1985
1986 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1987
1988 output_dict = {}
1989 for dut in input_dict.keys():
1990 if dut not in tgen.routers():
1991 continue
1992
1993 rnode = tgen.routers()[dut]
1994
1995 logger.info("[DUT: %s]: Verifying pim interface traffic", dut)
1996
1997 def show_pim_intf_traffic(rnode, dut, input_dict, output_dict):
1998 show_pim_intf_traffic_json = run_frr_cmd(
1999 rnode, "show ipv6 pim interface traffic json", isjson=True
2000 )
2001
2002 output_dict[dut] = {}
2003 for intf, data in input_dict[dut].items():
2004 interface_json = show_pim_intf_traffic_json[intf]
2005 for state in data:
2006
2007 # Verify Tx/Rx
2008 if state in interface_json:
2009 output_dict[dut][state] = interface_json[state]
2010 else:
2011 errormsg = (
2012 "[DUT %s]: %s is not present"
2013 "for interface %s [FAILED]!! " % (dut, state, intf)
2014 )
2015 return errormsg
2016 return None
2017
2018 test_func = functools.partial(
2019 show_pim_intf_traffic, rnode, dut, input_dict, output_dict
2020 )
2021 (result, out) = topotest.run_and_expect(test_func, None, count=20, wait=1)
2022 if not result:
2023 return out
2024
2025 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2026 return output_dict
2027
2028
de3d6b4d 2029@retry(retry_timeout=40, diag_pct=0)
a53c08bc 2030def verify_pim_interface(
d7032129 2031 tgen, topo, dut, interface=None, interface_ip=None, addr_type="ipv4", expected=True
a53c08bc 2032):
e8cd26fd 2033 """
2034 Verify all PIM interface are up and running, config is verified
2035 using "show ip pim interface" cli
2036
2037 Parameters
2038 ----------
2039 * `tgen`: topogen object
2040 * `topo` : json file data
2041 * `dut` : device under test
eab72dc8 2042 * `interface` : interface name
2043 * `interface_ip` : interface ip address
3c41ebf8 2044 * `expected` : expected results from API, by-default True
e8cd26fd 2045
2046 Usage
2047 -----
eab72dc8 2048 result = verify_pim_interfacetgen, topo, dut, interface=ens192, interface_ip=20.1.1.1)
e8cd26fd 2049
2050 Returns
2051 -------
2052 errormsg(str) or True
2053 """
2054
2055 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2056
2057 for router in tgen.routers():
2058 if router != dut:
2059 continue
2060
2061 logger.info("[DUT: %s]: Verifying PIM interface status:", dut)
2062
2063 rnode = tgen.routers()[dut]
d7032129
KK
2064
2065 if addr_type == "ipv4":
2066 addr_cmd = "ip"
2067 pim_cmd = "pim"
2068 elif addr_type == "ipv6":
2069 addr_cmd = "ipv6"
2070 pim_cmd = "pim6"
2071 show_pim_interface_json = rnode.vtysh_cmd(
2072 "show {} pim interface json".format(addr_cmd), isjson=True
5980ad0a 2073 )
eab72dc8 2074
d7032129 2075 logger.info("show_pim_interface_json: \n %s", show_pim_interface_json)
eab72dc8 2076
2077 if interface_ip:
d7032129
KK
2078 if interface in show_pim_interface_json:
2079 pim_intf_json = show_pim_interface_json[interface]
eab72dc8 2080 if pim_intf_json["address"] != interface_ip:
5980ad0a 2081 errormsg = (
d7032129
KK
2082 "[DUT %s]: %s interface "
2083 "%s is not correct "
5980ad0a 2084 "[FAILED]!! Expected : %s, Found : %s"
d7032129
KK
2085 % (
2086 dut,
2087 pim_cmd,
2088 addr_cmd,
2089 pim_intf_json["address"],
2090 interface_ip,
2091 )
5980ad0a 2092 )
eab72dc8 2093 return errormsg
2094 else:
5980ad0a 2095 logger.info(
d7032129
KK
2096 "[DUT %s]: %s interface "
2097 "%s is correct "
5980ad0a 2098 "[Passed]!! Expected : %s, Found : %s"
d7032129
KK
2099 % (
2100 dut,
2101 pim_cmd,
2102 addr_cmd,
2103 pim_intf_json["address"],
2104 interface_ip,
2105 )
5980ad0a 2106 )
eab72dc8 2107 return True
2108 else:
2109 for destLink, data in topo["routers"][dut]["links"].items():
2110 if "type" in data and data["type"] == "loopback":
2111 continue
e8cd26fd 2112
d7032129 2113 if pim_cmd in data and data[pim_cmd] == "enable":
eab72dc8 2114 pim_interface = data["interface"]
d7032129 2115 pim_intf_ip = data[addr_type].split("/")[0]
e8cd26fd 2116
d7032129
KK
2117 if pim_interface in show_pim_interface_json:
2118 pim_intf_json = show_pim_interface_json[pim_interface]
e46ce55e
KK
2119 else:
2120 errormsg = (
d7032129
KK
2121 "[DUT %s]: %s interface: %s "
2122 "PIM interface %s: %s, not Found"
2123 % (dut, pim_cmd, pim_interface, addr_cmd, pim_intf_ip)
e46ce55e
KK
2124 )
2125 return errormsg
e8cd26fd 2126
2127 # Verifying PIM interface
5980ad0a
DS
2128 if (
2129 pim_intf_json["address"] != pim_intf_ip
2130 and pim_intf_json["state"] != "up"
2131 ):
2132 errormsg = (
d7032129
KK
2133 "[DUT %s]: %s interface: %s "
2134 "PIM interface %s: %s, status check "
5980ad0a
DS
2135 "[FAILED]!! Expected : %s, Found : %s"
2136 % (
2137 dut,
d7032129 2138 pim_cmd,
5980ad0a 2139 pim_interface,
d7032129 2140 addr_cmd,
5980ad0a
DS
2141 pim_intf_ip,
2142 pim_interface,
2143 pim_intf_json["state"],
2144 )
2145 )
e8cd26fd 2146 return errormsg
2147
5980ad0a 2148 logger.info(
d7032129
KK
2149 "[DUT %s]: %s interface: %s, "
2150 "interface %s: %s, status: %s"
5980ad0a
DS
2151 " [PASSED]!!",
2152 dut,
d7032129 2153 pim_cmd,
5980ad0a 2154 pim_interface,
d7032129 2155 addr_cmd,
5980ad0a
DS
2156 pim_intf_ip,
2157 pim_intf_json["state"],
2158 )
e8cd26fd 2159
2160 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2161 return True
2162
2163
4fafd29f 2164def clear_pim_interface_traffic(tgen, topo):
e8cd26fd 2165 """
d7032129
KK
2166 Clear ip pim interface traffic by running
2167 "clear ip pim interface traffic" cli
e8cd26fd 2168
2169 Parameters
2170 ----------
2171 * `tgen`: topogen object
2172 Usage
2173 -----
2174
4fafd29f 2175 result = clear_pim_interface_traffic(tgen, topo)
e8cd26fd 2176
2177 Returns
2178 -------
2179 errormsg(str) or True
2180 """
2181
2182 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2183
2184 for dut in tgen.routers():
2185 if "pim" not in topo["routers"][dut]:
2186 continue
2187
2188 rnode = tgen.routers()[dut]
2189
2190 logger.info("[DUT: %s]: Clearing pim interface traffic", dut)
2191 result = run_frr_cmd(rnode, "clear ip pim interface traffic")
2192
2193 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2194
2195 return True
2196
2197
d7032129 2198def clear_pim6_interface_traffic(tgen, topo):
e8cd26fd 2199 """
d7032129
KK
2200 Clear ipv6 pim interface traffic by running
2201 "clear ipv6 pim interface traffic" cli
e8cd26fd 2202
2203 Parameters
2204 ----------
2205 * `tgen`: topogen object
e8cd26fd 2206 Usage
2207 -----
2208
d7032129 2209 result = clear_pim6_interface_traffic(tgen, topo)
e8cd26fd 2210
2211 Returns
2212 -------
2213 errormsg(str) or True
2214 """
2215
2216 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2217
d7032129
KK
2218 for dut in tgen.routers():
2219 if "pim" not in topo["routers"][dut]:
2220 continue
e8cd26fd 2221
d7032129 2222 rnode = tgen.routers()[dut]
e8cd26fd 2223
d7032129
KK
2224 logger.info("[DUT: %s]: Clearing pim6 interface traffic", dut)
2225 result = run_frr_cmd(rnode, "clear ipv6 pim interface traffic")
e8cd26fd 2226
d7032129 2227 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
e8cd26fd 2228
d7032129 2229 return True
e8cd26fd 2230
e8cd26fd 2231
d7032129
KK
2232def clear_pim6_interfaces(tgen, topo):
2233 """
2234 Clear ipv6 pim interface by running
2235 "clear ipv6 pim interface" cli
e8cd26fd 2236
d7032129
KK
2237 Parameters
2238 ----------
2239 * `tgen`: topogen object
2240 Usage
2241 -----
2242
2243 result = clear_pim6_interfaces(tgen, topo)
2244
2245 Returns
2246 -------
2247 errormsg(str) or True
2248 """
2249
2250 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2251
2252 for dut in tgen.routers():
2253 if "pim" not in topo["routers"][dut]:
2254 continue
2255
2256 rnode = tgen.routers()[dut]
2257
2258 logger.info("[DUT: %s]: Clearing pim6 interfaces", dut)
2259 result = run_frr_cmd(rnode, "clear ipv6 pim interface")
2260
2261 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2262
2263 return True
2264
2265
2266def clear_pim_interfaces(tgen, dut):
2267 """
2268 Clear ip/ipv6 pim interface by running
2269 "clear ip/ipv6 pim interfaces" cli
2270
2271 Parameters
2272 ----------
2273 * `tgen`: topogen object
2274 * `dut`: Device Under Test
2275 Usage
2276 -----
2277
2278 result = clear_pim_interfaces(tgen, dut)
2279
2280 Returns
2281 -------
2282 errormsg(str) or True
2283 """
2284
2285 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2286
2287 nh_before_clear = {}
2288 nh_after_clear = {}
2289
2290 rnode = tgen.routers()[dut]
2291
2292 logger.info("[DUT: %s]: Verify pim neighbor before pim" " neighbor clear", dut)
2293 # To add uptime initially
2294 sleep(10)
2295 run_json_before = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
2296
2297 for key, value in run_json_before.items():
2298 if bool(value):
2299 for _key, _value in value.items():
2300 nh_before_clear[key] = _value["upTime"]
2301
2302 # Clearing PIM neighbors
2303 logger.info("[DUT: %s]: Clearing pim interfaces", dut)
2304 run_frr_cmd(rnode, "clear ip pim interfaces")
2305
2306 logger.info("[DUT: %s]: Verify pim neighbor after pim" " neighbor clear", dut)
2307
2308 found = False
2309
2310 # Waiting for maximum 60 sec
2311 fail_intf = []
2312 for retry in range(1, 13):
2313 sleep(5)
2314 logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut)
2315 run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
2316 found = True
2317 for pim_intf in nh_before_clear.keys():
2318 if pim_intf not in run_json_after or not run_json_after[pim_intf]:
2319 found = False
e8cd26fd 2320 fail_intf.append(pim_intf)
2321
2322 if found is True:
2323 break
2324 else:
2325 errormsg = (
2326 "[DUT: %s]: pim neighborship is not formed for %s"
2327 "after clear_ip_pim_interfaces %s [FAILED!!]",
2328 dut,
2329 fail_intf,
2330 )
2331 return errormsg
2332
2333 for key, value in run_json_after.items():
2334 if bool(value):
2335 for _key, _value in value.items():
2336 nh_after_clear[key] = _value["upTime"]
2337
2338 # Verify uptime for neighbors
2339 for pim_intf in nh_before_clear.keys():
2340 d1 = datetime.datetime.strptime(nh_before_clear[pim_intf], "%H:%M:%S")
2341 d2 = datetime.datetime.strptime(nh_after_clear[pim_intf], "%H:%M:%S")
2342 if d2 >= d1:
2343 errormsg = (
2344 "[DUT: %s]: PIM neighborship is not cleared for",
2345 " interface %s [FAILED!!]",
2346 dut,
2347 pim_intf,
2348 )
2349
2350 logger.info("[DUT: %s]: PIM neighborship is cleared [PASSED!!]")
2351
2352 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2353
2354 return True
2355
2356
4fafd29f 2357def clear_igmp_interfaces(tgen, dut):
e8cd26fd 2358 """
4fafd29f
KK
2359 Clear ip/ipv6 igmp interfaces by running
2360 "clear ip/ipv6 igmp interfaces" cli
e8cd26fd 2361
2362 Parameters
2363 ----------
2364 * `tgen`: topogen object
2365 * `dut`: device under test
2366
2367 Usage
2368 -----
2369 dut = "r1"
4fafd29f 2370 result = clear_igmp_interfaces(tgen, dut)
e8cd26fd 2371 Returns
2372 -------
2373 errormsg(str) or True
2374 """
2375
2376 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2377
2378 group_before_clear = {}
2379 group_after_clear = {}
2380
2381 rnode = tgen.routers()[dut]
2382
2383 logger.info("[DUT: %s]: IGMP group uptime before clear" " igmp groups:", dut)
2384 igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
2385
2386 total_groups_before_clear = igmp_json["totalGroups"]
2387
2388 for key, value in igmp_json.items():
2389 if type(value) is not dict:
2390 continue
2391
2392 groups = value["groups"]
2393 group = groups[0]["group"]
2394 uptime = groups[0]["uptime"]
2395 group_before_clear[group] = uptime
2396
2397 logger.info("[DUT: %s]: Clearing ip igmp interfaces", dut)
2398 result = run_frr_cmd(rnode, "clear ip igmp interfaces")
2399
2400 # Waiting for maximum 60 sec
2401 for retry in range(1, 13):
2402 logger.info(
2403 "[DUT: %s]: Waiting for 5 sec for igmp interfaces" " to come up", dut
2404 )
2405 sleep(5)
2406 igmp_json = run_frr_cmd(rnode, "show ip igmp groups json", isjson=True)
2407
2408 total_groups_after_clear = igmp_json["totalGroups"]
2409
2410 if total_groups_before_clear == total_groups_after_clear:
2411 break
2412
2413 for key, value in igmp_json.items():
2414 if type(value) is not dict:
2415 continue
2416
2417 groups = value["groups"]
2418 group = groups[0]["group"]
2419 uptime = groups[0]["uptime"]
2420 group_after_clear[group] = uptime
2421
2422 # Verify uptime for groups
2423 for group in group_before_clear.keys():
2424 d1 = datetime.datetime.strptime(group_before_clear[group], "%H:%M:%S")
2425 d2 = datetime.datetime.strptime(group_after_clear[group], "%H:%M:%S")
2426 if d2 >= d1:
2427 errormsg = ("[DUT: %s]: IGMP group is not cleared", " [FAILED!!]", dut)
2428
2429 logger.info("[DUT: %s]: IGMP group is cleared [PASSED!!]")
2430
2431 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2432
2433 return True
2434
2435
ed776e38 2436@retry(retry_timeout=20)
4fafd29f 2437def clear_mroute_verify(tgen, dut, expected=True):
e8cd26fd 2438 """
4fafd29f 2439 Clear ip/ipv6 mroute by running "clear ip/ipv6 mroute" cli and verify
e8cd26fd 2440 mroutes are up again after mroute clear
2441
2442 Parameters
2443 ----------
2444 * `tgen`: topogen object
2445 * `dut`: Device Under Test
3c41ebf8
KK
2446 * `expected` : expected results from API, by-default True
2447
e8cd26fd 2448 Usage
2449 -----
2450
4fafd29f 2451 result = clear_mroute_verify(tgen, dut)
e8cd26fd 2452
2453 Returns
2454 -------
2455 errormsg(str) or True
2456 """
2457
2458 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2459
2460 mroute_before_clear = {}
2461 mroute_after_clear = {}
2462
2463 rnode = tgen.routers()[dut]
2464
e8cd26fd 2465 logger.info("[DUT: %s]: IP mroutes uptime before clear", dut)
2466 mroute_json_1 = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
2467
2468 for group in mroute_json_1.keys():
2469 mroute_before_clear[group] = {}
2470 for key in mroute_json_1[group].keys():
2471 for _key, _value in mroute_json_1[group][key]["oil"].items():
2472 if _key != "pimreg":
2473 mroute_before_clear[group][key] = _value["upTime"]
2474
2475 logger.info("[DUT: %s]: Clearing ip mroute", dut)
2476 result = run_frr_cmd(rnode, "clear ip mroute")
2477
2478 # RFC 3376: 8.2. Query Interval - Default: 125 seconds
2479 # So waiting for maximum 130 sec to get the igmp report
2480 for retry in range(1, 26):
2481 logger.info("[DUT: %s]: Waiting for 2 sec for mroutes" " to come up", dut)
2482 sleep(5)
2483 keys_json1 = mroute_json_1.keys()
2484 mroute_json_2 = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
2485
2486 if bool(mroute_json_2):
2487 keys_json2 = mroute_json_2.keys()
2488
2489 for group in mroute_json_2.keys():
2490 flag = False
2491 for key in mroute_json_2[group].keys():
2492 if "oil" not in mroute_json_2[group]:
2493 continue
2494
2495 for _key, _value in mroute_json_2[group][key]["oil"].items():
2496 if _key != "pimreg" and keys_json1 == keys_json2:
2497 break
2498 flag = True
2499 if flag:
2500 break
2501 else:
2502 continue
2503
2504 for group in mroute_json_2.keys():
2505 mroute_after_clear[group] = {}
2506 for key in mroute_json_2[group].keys():
2507 for _key, _value in mroute_json_2[group][key]["oil"].items():
2508 if _key != "pimreg":
2509 mroute_after_clear[group][key] = _value["upTime"]
2510
2511 # Verify uptime for mroute
2512 for group in mroute_before_clear.keys():
2513 for source in mroute_before_clear[group].keys():
2514 if set(mroute_before_clear[group]) != set(mroute_after_clear[group]):
2515 errormsg = (
2516 "[DUT: %s]: mroute (%s, %s) has not come"
2517 " up after mroute clear [FAILED!!]" % (dut, source, group)
2518 )
2519 return errormsg
2520
2521 d1 = datetime.datetime.strptime(
2522 mroute_before_clear[group][source], "%H:%M:%S"
2523 )
2524 d2 = datetime.datetime.strptime(
2525 mroute_after_clear[group][source], "%H:%M:%S"
2526 )
2527 if d2 >= d1:
2528 errormsg = "[DUT: %s]: IP mroute is not cleared" " [FAILED!!]" % (dut)
2529
2530 logger.info("[DUT: %s]: IP mroute is cleared [PASSED!!]", dut)
2531
2532 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2533
2534 return True
2535
2536
4fafd29f 2537def clear_mroute(tgen, dut=None):
e8cd26fd 2538 """
4fafd29f 2539 Clear ip/ipv6 mroute by running "clear ip mroute" cli
e8cd26fd 2540
2541 Parameters
2542 ----------
2543 * `tgen`: topogen object
2544 * `dut`: device under test, default None
2545
2546 Usage
2547 -----
4fafd29f 2548 clear_mroute(tgen, dut)
e8cd26fd 2549 """
2550
2551 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2552
2553 router_list = tgen.routers()
2554 for router, rnode in router_list.items():
2555 if dut is not None and router != dut:
2556 continue
2557
2558 logger.debug("[DUT: %s]: Clearing ip mroute", router)
2559 rnode.vtysh_cmd("clear ip mroute")
2560
2561 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2562
2563
d7032129
KK
2564def clear_pim6_mroute(tgen, dut=None):
2565 """
2566 Clear ipv6 mroute by running "clear ipv6 mroute" cli
2567
2568 Parameters
2569 ----------
2570 * `tgen`: topogen object
2571 * `dut`: device under test, default None
2572
2573 Usage
2574 -----
2575 clear_mroute(tgen, dut)
2576 """
2577
2578 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2579
2580 router_list = tgen.routers()
2581 for router, rnode in router_list.items():
2582 if dut is not None and router != dut:
2583 continue
2584
2585 logger.debug("[DUT: %s]: Clearing ipv6 mroute", router)
2586 rnode.vtysh_cmd("clear ipv6 mroute")
2587
2588 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2589
2590 return True
2591
2592
e8cd26fd 2593def reconfig_interfaces(tgen, topo, senderRouter, receiverRouter, packet=None):
2594 """
2595 Configure interface ip for sender and receiver routers
2596 as per bsr packet
2597
2598 Parameters
2599 ----------
2600 * `tgen` : Topogen object
2601 * `topo` : json file data
2602 * `senderRouter` : Sender router
2603 * `receiverRouter` : Receiver router
2604 * `packet` : BSR packet in raw format
2605
2606 Returns
2607 -------
2608 True or False
2609 """
2610 result = False
2611 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2612
2613 try:
2614 config_data = []
2615
2616 src_ip = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["src_ip"]
2617 dest_ip = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["dest_ip"]
2618
2619 for destLink, data in topo["routers"][senderRouter]["links"].items():
2620 if "type" in data and data["type"] == "loopback":
2621 continue
2622
2623 if "pim" in data and data["pim"] == "enable":
2624 sender_interface = data["interface"]
2625 sender_interface_ip = data["ipv4"]
2626
2627 config_data.append("interface {}".format(sender_interface))
2628 config_data.append("no ip address {}".format(sender_interface_ip))
2629 config_data.append("ip address {}".format(src_ip))
2630
2631 result = create_common_configuration(
2632 tgen, senderRouter, config_data, "interface_config"
2633 )
2634 if result is not True:
2635 return False
2636
2637 config_data = []
2638 links = topo["routers"][destLink]["links"]
2639 pim_neighbor = {key: links[key] for key in [senderRouter]}
2640
2641 data = pim_neighbor[senderRouter]
2642 if "type" in data and data["type"] == "loopback":
2643 continue
2644
2645 if "pim" in data and data["pim"] == "enable":
2646 receiver_interface = data["interface"]
2647 receiver_interface_ip = data["ipv4"]
2648
2649 config_data.append("interface {}".format(receiver_interface))
2650 config_data.append("no ip address {}".format(receiver_interface_ip))
2651 config_data.append("ip address {}".format(dest_ip))
2652
2653 result = create_common_configuration(
2654 tgen, receiverRouter, config_data, "interface_config"
2655 )
2656 if result is not True:
2657 return False
2658
2659 except InvalidCLIError:
2660 # Traceback
2661 errormsg = traceback.format_exc()
2662 logger.error(errormsg)
2663 return errormsg
2664
2665 logger.debug("Exiting lib API: reconfig_interfaces()")
2666 return result
2667
2668
2669def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping):
2670 """
2671 Add physical interfaces tp RP for all the RPs
2672
2673 Parameters
2674 ----------
2675 * `tgen` : Topogen object
2676 * `topo` : json file data
2677 * `interface` : RP interface
2678 * `rp` : rp for given topology
2679 * `rp_mapping` : dictionary of all groups and RPs
2680
2681 Returns
2682 -------
2683 True or False
2684 """
2685 result = False
2686 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2687
2688 try:
2689 config_data = []
2690
2691 for group, rp_list in rp_mapping.items():
2692 for _rp in rp_list:
2693 config_data.append("interface {}".format(interface))
2694 config_data.append("ip address {}".format(_rp))
2695 config_data.append("ip pim")
2696
4f99894d 2697 # Why not config just once, why per group?
e8cd26fd 2698 result = create_common_configuration(
2699 tgen, rp, config_data, "interface_config"
2700 )
2701 if result is not True:
2702 return False
2703
2704 except InvalidCLIError:
2705 # Traceback
2706 errormsg = traceback.format_exc()
2707 logger.error(errormsg)
2708 return errormsg
2709
8ab46256 2710 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
e8cd26fd 2711 return result
2712
2713
49581587 2714def scapy_send_bsr_raw_packet(tgen, topo, senderRouter, receiverRouter, packet=None):
e8cd26fd 2715 """
2716 Using scapy Raw() method to send BSR raw packet from one FRR
2717 to other
2718
2719 Parameters:
2720 -----------
2721 * `tgen` : Topogen object
2722 * `topo` : json file data
2723 * `senderRouter` : Sender router
2724 * `receiverRouter` : Receiver router
2725 * `packet` : BSR packet in raw format
e8cd26fd 2726
2727 returns:
2728 --------
2729 errormsg or True
2730 """
2731
2732 global CWD
2733 result = ""
2734 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2735
49581587
CH
2736 python3_path = tgen.net.get_exec_path(["python3", "python"])
2737 script_path = os.path.join(CWD, "send_bsr_packet.py")
2738 node = tgen.net[senderRouter]
e8cd26fd 2739
2740 for destLink, data in topo["routers"][senderRouter]["links"].items():
2741 if "type" in data and data["type"] == "loopback":
2742 continue
2743
2744 if "pim" in data and data["pim"] == "enable":
2745 sender_interface = data["interface"]
2746
2747 packet = topo["routers"][senderRouter]["bsm"]["bsr_packets"][packet]["data"]
2748
49581587
CH
2749 cmd = [
2750 python3_path,
2751 script_path,
2752 packet,
2753 sender_interface,
2754 "--interval=1",
2755 "--count=1",
2756 ]
e8cd26fd 2757 logger.info("Scapy cmd: \n %s", cmd)
49581587 2758 node.cmd_raises(cmd)
e8cd26fd 2759
2760 logger.debug("Exiting lib API: scapy_send_bsr_raw_packet")
2761 return True
2762
2763
2764def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None):
2765 """
2766 Find which RP is having lowest prioriy and returns rp IP
2767
2768 Parameters
2769 ----------
2770 * `tgen`: topogen object
2771 * `dut`: device under test
2772 * `bsr`: BSR address
2773 * 'grp': Group Address
2774
2775 Usage
2776 -----
2777 dut = "r1"
2778 result = verify_pim_rp_info(tgen, dut, bsr)
2779
2780 Returns:
2781 dictionary: group and RP, which has to be installed as per
2782 lowest priority or highest priority
2783 """
2784
2785 rp_details = {}
2786 rnode = tgen.routers()[dut]
2787
2788 logger.info("[DUT: %s]: Fetching rp details from bsrp-info", dut)
2789 bsrp_json = run_frr_cmd(rnode, "show ip pim bsrp-info json", isjson=True)
2790
2791 if grp not in bsrp_json:
2792 return {}
2793
2794 for group, rp_data in bsrp_json.items():
2795 if group == "BSR Address" and bsrp_json["BSR Address"] == bsr:
2796 continue
2797
2798 if group != grp:
2799 continue
2800
2801 rp_priority = {}
2802 rp_hash = {}
2803
2804 for rp, value in rp_data.items():
2805 if rp == "Pending RP count":
2806 continue
2807 rp_priority[value["Rp Address"]] = value["Rp Priority"]
2808 rp_hash[value["Rp Address"]] = value["Hash Val"]
2809
2810 priority_dict = dict(zip(rp_priority.values(), rp_priority.keys()))
2811 hash_dict = dict(zip(rp_hash.values(), rp_hash.keys()))
2812
2813 # RP with lowest priority
2814 if len(priority_dict) != 1:
2815 rp_p, lowest_priority = sorted(rp_priority.items(), key=lambda x: x[1])[0]
2816 rp_details[group] = rp_p
2817
2818 # RP with highest hash value
2819 if len(priority_dict) == 1:
2820 rp_h, highest_hash = sorted(rp_hash.items(), key=lambda x: x[1])[-1]
2821 rp_details[group] = rp_h
2822
2823 # RP with highest IP address
2824 if len(priority_dict) == 1 and len(hash_dict) == 1:
2825 rp_details[group] = sorted(rp_priority.keys())[-1]
2826
2827 return rp_details
2828
2829
ed776e38 2830@retry(retry_timeout=12)
a53c08bc
CH
2831def verify_pim_grp_rp_source(
2832 tgen, topo, dut, grp_addr, rp_source, rpadd=None, expected=True
2833):
e8cd26fd 2834 """
2835 Verify pim rp info by running "show ip pim rp-info" cli
2836
2837 Parameters
2838 ----------
2839 * `tgen`: topogen object
2840 * `topo`: JSON file handler
2841 * `dut`: device under test
2842 * `grp_addr`: IGMP group address
2843 * 'rp_source': source from which rp installed
2844 * 'rpadd': rp address
3c41ebf8 2845 * `expected` : expected results from API, by-default True
e8cd26fd 2846
2847 Usage
2848 -----
2849 dut = "r1"
2850 group_address = "225.1.1.1"
2851 rp_source = "BSR"
2852 result = verify_pim_rp_and_source(tgen, topo, dut, group_address, rp_source)
2853
2854 Returns
2855 -------
2856 errormsg(str) or True
2857 """
2858
2859 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2860
2861 if dut not in tgen.routers():
2862 return False
2863
2864 rnode = tgen.routers()[dut]
2865
2866 logger.info("[DUT: %s]: Verifying ip rp info", dut)
2867 show_ip_rp_info_json = run_frr_cmd(rnode, "show ip pim rp-info json", isjson=True)
2868
2869 if rpadd != None:
2870 rp_json = show_ip_rp_info_json[rpadd]
2871 if rp_json[0]["group"] == grp_addr:
2872 if rp_json[0]["source"] == rp_source:
2873 logger.info(
2874 "[DUT %s]: Verifying Group and rp_source [PASSED]"
2875 "Found Expected: %s, %s"
2876 % (dut, rp_json[0]["group"], rp_json[0]["source"])
2877 )
2878 return True
2879 else:
2880 errormsg = (
2881 "[DUT %s]: Verifying Group and rp_source [FAILED]"
2882 "Expected (%s, %s) "
2883 "Found (%s, %s)"
2884 % (
2885 dut,
2886 grp_addr,
2887 rp_source,
2888 rp_json[0]["group"],
2889 rp_json[0]["source"],
2890 )
2891 )
2892 return errormsg
2893 errormsg = (
2894 "[DUT %s]: Verifying Group and rp_source [FAILED]"
2895 "Expected: %s, %s but not found" % (dut, grp_addr, rp_source)
2896 )
2897 return errormsg
2898
2899 for rp in show_ip_rp_info_json:
2900 rp_json = show_ip_rp_info_json[rp]
2901 logger.info("%s", rp_json)
2902 if rp_json[0]["group"] == grp_addr:
2903 if rp_json[0]["source"] == rp_source:
2904 logger.info(
2905 "[DUT %s]: Verifying Group and rp_source [PASSED]"
2906 "Found Expected: %s, %s"
2907 % (dut, rp_json[0]["group"], rp_json[0]["source"])
2908 )
2909 return True
2910 else:
2911 errormsg = (
2912 "[DUT %s]: Verifying Group and rp_source [FAILED]"
2913 "Expected (%s, %s) "
2914 "Found (%s, %s)"
2915 % (
2916 dut,
2917 grp_addr,
2918 rp_source,
2919 rp_json[0]["group"],
2920 rp_json[0]["source"],
2921 )
2922 )
2923 return errormsg
2924
2925 errormsg = (
2926 "[DUT %s]: Verifying Group and rp_source [FAILED]"
2927 "Expected: %s, %s but not found" % (dut, grp_addr, rp_source)
2928 )
2929
2930 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2931
2932 return errormsg
2933
2934
de3d6b4d 2935@retry(retry_timeout=60, diag_pct=0)
3c41ebf8 2936def verify_pim_bsr(tgen, topo, dut, bsr_ip, expected=True):
e8cd26fd 2937 """
2938 Verify all PIM interface are up and running, config is verified
2939 using "show ip pim interface" cli
2940
2941 Parameters
2942 ----------
2943 * `tgen`: topogen object
2944 * `topo` : json file data
2945 * `dut` : device under test
2946 * 'bsr' : bsr ip to be verified
3c41ebf8 2947 * `expected` : expected results from API, by-default True
e8cd26fd 2948
2949 Usage
2950 -----
2951 result = verify_pim_bsr(tgen, topo, dut, bsr_ip)
2952
2953 Returns
2954 -------
2955 errormsg(str) or True
2956 """
2957
2958 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2959
2960 for router in tgen.routers():
2961 if router != dut:
2962 continue
2963
2964 logger.info("[DUT: %s]: Verifying PIM bsr status:", dut)
2965
2966 rnode = tgen.routers()[dut]
2967 pim_bsr_json = rnode.vtysh_cmd("show ip pim bsr json", isjson=True)
2968
2969 logger.info("show_ip_pim_bsr_json: \n %s", pim_bsr_json)
2970
2971 # Verifying PIM bsr
2972 if pim_bsr_json["bsr"] != bsr_ip:
2973 errormsg = (
2974 "[DUT %s]:"
2975 "bsr status: not found"
2976 "[FAILED]!! Expected : %s, Found : %s"
2977 % (dut, bsr_ip, pim_bsr_json["bsr"])
2978 )
2979 return errormsg
2980
2981 logger.info(
2982 "[DUT %s]:" " bsr status: found, Address :%s" " [PASSED]!!",
2983 dut,
2984 pim_bsr_json["bsr"],
2985 )
2986
2987 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2988 return True
2989
2990
de3d6b4d 2991@retry(retry_timeout=60, diag_pct=0)
4fafd29f 2992def verify_pim_upstream_rpf(
a53c08bc
CH
2993 tgen, topo, dut, interface, group_addresses, rp=None, expected=True
2994):
e8cd26fd 2995 """
4fafd29f
KK
2996 Verify IP/IPv6 PIM upstream rpf, config is verified
2997 using "show ip/ipv6 pim neighbor" cli
e8cd26fd 2998
2999 Parameters
3000 ----------
3001 * `tgen`: topogen object
3002 * `topo` : json file data
3003 * `dut` : devuce under test
3004 * `interface` : upstream interface
3005 * `group_addresses` : list of group address for which upstream info
3006 needs to be checked
3007 * `rp` : RP address
3c41ebf8 3008 * `expected` : expected results from API, by-default True
e8cd26fd 3009
3010 Usage
3011 -----
4fafd29f 3012 result = verify_pim_upstream_rpf(gen, topo, dut, interface,
e8cd26fd 3013 group_addresses, rp=None)
3014
3015 Returns
3016 -------
3017 errormsg(str) or True
3018 """
3019
3020 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3021
3022 if "pim" in topo["routers"][dut]:
3023
3024 logger.info("[DUT: %s]: Verifying ip pim upstream rpf:", dut)
3025
3026 rnode = tgen.routers()[dut]
3027 show_ip_pim_upstream_rpf_json = rnode.vtysh_cmd(
3028 "show ip pim upstream-rpf json", isjson=True
3029 )
3030
3031 logger.info(
3032 "show_ip_pim_upstream_rpf_json: \n %s", show_ip_pim_upstream_rpf_json
3033 )
3034
3035 if type(group_addresses) is not list:
3036 group_addresses = [group_addresses]
3037
3038 for grp_addr in group_addresses:
3039 for destLink, data in topo["routers"][dut]["links"].items():
3040 if "type" in data and data["type"] == "loopback":
3041 continue
3042
3043 if "pim" not in topo["routers"][destLink]:
3044 continue
3045
3046 # Verify RP info
3047 if rp is None:
3048 rp_details = find_rp_details(tgen, topo)
3049 else:
660c59ed 3050 rp_details = {dut: rp}
e8cd26fd 3051
3052 if dut in rp_details:
3053 pim_nh_intf_ip = topo["routers"][dut]["links"]["lo"]["ipv4"].split(
3054 "/"
3055 )[0]
3056 else:
3057 if destLink not in interface:
3058 continue
3059
3060 links = topo["routers"][destLink]["links"]
3061 pim_neighbor = {key: links[key] for key in [dut]}
3062
3063 data = pim_neighbor[dut]
3064 if "pim" in data and data["pim"] == "enable":
3065 pim_nh_intf_ip = data["ipv4"].split("/")[0]
3066
3067 upstream_rpf_json = show_ip_pim_upstream_rpf_json[grp_addr]["*"]
3068
3069 # Verifying ip pim upstream rpf
3070 if (
3071 upstream_rpf_json["rpfInterface"] == interface
3072 and upstream_rpf_json["ribNexthop"] != pim_nh_intf_ip
3073 ):
3074 errormsg = (
3075 "[DUT %s]: Verifying group: %s, "
3076 "rpf interface: %s, "
3077 " rib Nexthop check [FAILED]!!"
3078 "Expected: %s, Found: %s"
3079 % (
3080 dut,
3081 grp_addr,
3082 interface,
3083 pim_nh_intf_ip,
3084 upstream_rpf_json["ribNexthop"],
3085 )
3086 )
3087 return errormsg
3088
3089 logger.info(
3090 "[DUT %s]: Verifying group: %s,"
3091 " rpf interface: %s, "
3092 " rib Nexthop: %s [PASSED]!!",
3093 dut,
3094 grp_addr,
3095 interface,
3096 pim_nh_intf_ip,
3097 )
3098
3099 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3100 return True
3101
3102
3103def enable_disable_pim_unicast_bsm(tgen, router, intf, enable=True):
3104 """
3105 Helper API to enable or disable pim bsm on interfaces
3106
3107 Parameters
3108 ----------
3109 * `tgen` : Topogen object
3110 * `router` : router id to be configured.
3111 * `intf` : Interface to be configured
3112 * `enable` : this flag denotes if config should be enabled or disabled
3113
3114 Returns
3115 -------
3116 True or False
3117 """
3118 result = False
3119 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3120
3121 try:
3122 config_data = []
3123 cmd = "interface {}".format(intf)
3124 config_data.append(cmd)
3125
3126 if enable == True:
3127 config_data.append("ip pim unicast-bsm")
3128 else:
3129 config_data.append("no ip pim unicast-bsm")
3130
3131 result = create_common_configuration(
3132 tgen, router, config_data, "interface_config", build=False
3133 )
3134 if result is not True:
3135 return False
3136
3137 except InvalidCLIError:
3138 # Traceback
3139 errormsg = traceback.format_exc()
3140 logger.error(errormsg)
3141 return errormsg
3142
3143 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3144 return result
3145
3146
3147def enable_disable_pim_bsm(tgen, router, intf, enable=True):
3148 """
3149 Helper API to enable or disable pim bsm on interfaces
3150
3151 Parameters
3152 ----------
3153 * `tgen` : Topogen object
3154 * `router` : router id to be configured.
3155 * `intf` : Interface to be configured
3156 * `enable` : this flag denotes if config should be enabled or disabled
3157
3158 Returns
3159 -------
3160 True or False
3161 """
3162 result = False
3163 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3164
3165 try:
3166 config_data = []
3167 cmd = "interface {}".format(intf)
3168 config_data.append(cmd)
3169
3170 if enable is True:
3171 config_data.append("ip pim bsm")
3172 else:
3173 config_data.append("no ip pim bsm")
3174
3175 result = create_common_configuration(
3176 tgen, router, config_data, "interface_config", build=False
3177 )
3178 if result is not True:
3179 return False
3180
3181 except InvalidCLIError:
3182 # Traceback
3183 errormsg = traceback.format_exc()
3184 logger.error(errormsg)
3185 return errormsg
3186
3187 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3188 return result
3189
3190
de3d6b4d 3191@retry(retry_timeout=60, diag_pct=0)
4fafd29f 3192def verify_pim_join(
d7032129
KK
3193 tgen,
3194 topo,
3195 dut,
3196 interface,
3197 group_addresses,
3198 src_address=None,
3199 addr_type="ipv4",
3200 expected=True,
a53c08bc 3201):
e8cd26fd 3202 """
4fafd29f 3203 Verify ip/ipv6 pim join by running "show ip/ipv6 pim join" cli
e8cd26fd 3204
3205 Parameters
3206 ----------
3207 * `tgen`: topogen object
3208 * `topo`: JSON file handler
3209 * `dut`: device under test
3210 * `interface`: interface name, from which PIM join would come
3211 * `group_addresses`: IGMP group address
3212 * `src_address`: Source address
3c41ebf8 3213 * `expected` : expected results from API, by-default True
e8cd26fd 3214
3215 Usage
3216 -----
3217 dut = "r1"
3218 interface = "r1-r0-eth0"
3219 group_address = "225.1.1.1"
4fafd29f 3220 result = verify_pim_join(tgen, dut, star, group_address, interface)
e8cd26fd 3221
3222 Returns
3223 -------
3224 errormsg(str) or True
3225 """
3226 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3227
3228 if dut not in tgen.routers():
3229 return False
3230
3231 rnode = tgen.routers()[dut]
3232
3233 logger.info("[DUT: %s]: Verifying pim join", dut)
e8cd26fd 3234
3235 if type(group_addresses) is not list:
3236 group_addresses = [group_addresses]
3237
d7032129
KK
3238 for grp in group_addresses:
3239 addr_type = validate_ip_address(grp)
3240
3241 if addr_type == "ipv4":
3242 ip_cmd = "ip"
3243 elif addr_type == "ipv6":
3244 ip_cmd = "ipv6"
3245
3246 show_pim_join_json = run_frr_cmd(
3247 rnode, "show {} pim join json".format(ip_cmd), isjson=True
3248 )
3249
e8cd26fd 3250 for grp_addr in group_addresses:
3251 # Verify if IGMP is enabled in DUT
3252 if "igmp" not in topo["routers"][dut]:
3253 pim_join = True
3254 else:
3255 pim_join = False
3256
3257 interface_json = show_pim_join_json[interface]
3258
3259 grp_addr = grp_addr.split("/")[0]
3260 for source, data in interface_json[grp_addr].items():
3261
3262 # Verify pim join
3263 if pim_join:
3264 if data["group"] == grp_addr and data["channelJoinName"] == "JOIN":
3265 logger.info(
3266 "[DUT %s]: Verifying pim join for group: %s"
3267 "[PASSED]!! Found Expected: (%s)",
3268 dut,
3269 grp_addr,
3270 data["channelJoinName"],
3271 )
3272 else:
3273 errormsg = (
3274 "[DUT %s]: Verifying pim join for group: %s"
3275 "[FAILED]!! Expected: (%s) "
3276 "Found: (%s)" % (dut, grp_addr, "JOIN", data["channelJoinName"])
3277 )
3278 return errormsg
3279
3280 if not pim_join:
3281 if data["group"] == grp_addr and data["channelJoinName"] == "NOINFO":
3282 logger.info(
3283 "[DUT %s]: Verifying pim join for group: %s"
3284 "[PASSED]!! Found Expected: (%s)",
3285 dut,
3286 grp_addr,
3287 data["channelJoinName"],
3288 )
3289 else:
3290 errormsg = (
3291 "[DUT %s]: Verifying pim join for group: %s"
3292 "[FAILED]!! Expected: (%s) "
3293 "Found: (%s)"
3294 % (dut, grp_addr, "NOINFO", data["channelJoinName"])
3295 )
3296 return errormsg
3297
3298 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3299 return True
3300
3301
de3d6b4d 3302@retry(retry_timeout=60, diag_pct=0)
3c41ebf8 3303def verify_igmp_config(tgen, input_dict, stats_return=False, expected=True):
e8cd26fd 3304 """
3305 Verify igmp interface details, verifying following configs:
3306 timerQueryInterval
3307 timerQueryResponseIntervalMsec
3308 lastMemberQueryCount
3309 timerLastMemberQueryMsec
3310
3311 Parameters
3312 ----------
3313 * `tgen`: topogen object
3314 * `input_dict` : Input dict data, required to verify
3315 timer
3316 * `stats_return`: If user wants API to return statistics
3c41ebf8 3317 * `expected` : expected results from API, by-default True
e8cd26fd 3318
3319 Usage
3320 -----
3321 input_dict ={
3322 "l1": {
3323 "igmp": {
3324 "interfaces": {
3325 "l1-i1-eth1": {
3326 "igmp": {
3327 "query": {
3328 "query-interval" : 200,
3329 "query-max-response-time" : 100
3330 },
3331 "statistics": {
3332 "queryV2" : 2,
3333 "reportV2" : 1
3334 }
3335 }
3336 }
3337 }
3338 }
3339 }
3340 }
3341 result = verify_igmp_config(tgen, input_dict, stats_return)
3342
3343 Returns
3344 -------
3345 errormsg(str) or True
3346 """
3347
3348 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3349
3350 for dut in input_dict.keys():
3351 rnode = tgen.routers()[dut]
3352
3353 for interface, data in input_dict[dut]["igmp"]["interfaces"].items():
3354
3355 statistics = False
3356 report = False
3357 if "statistics" in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"]:
3358 statistics = True
3359 cmd = "show ip igmp statistics"
3360 else:
3361 cmd = "show ip igmp"
3362
3363 logger.info(
3364 "[DUT: %s]: Verifying IGMP interface %s detail:", dut, interface
3365 )
3366
3367 if statistics:
3368 if (
3369 "report"
3370 in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"][
3371 "statistics"
3372 ]
3373 ):
3374 report = True
3375
3376 if statistics and report:
3377 show_ip_igmp_intf_json = run_frr_cmd(
5aab262b 3378 rnode, "{} json".format(cmd), isjson=True
e8cd26fd 3379 )
3380 intf_detail_json = show_ip_igmp_intf_json["global"]
3381 else:
3382 show_ip_igmp_intf_json = run_frr_cmd(
3383 rnode, "{} interface {} json".format(cmd, interface), isjson=True
3384 )
3385
3386 if not report:
3387 if interface not in show_ip_igmp_intf_json:
3388 errormsg = (
3389 "[DUT %s]: IGMP interface: %s "
3390 " is not present in CLI output "
3391 "[FAILED]!! " % (dut, interface)
3392 )
3393 return errormsg
3394
3395 else:
3396 intf_detail_json = show_ip_igmp_intf_json[interface]
3397
3398 if stats_return:
3399 igmp_stats = {}
3400
3401 if "statistics" in data["igmp"]:
3402 if stats_return:
3403 igmp_stats["statistics"] = {}
3404 for query, value in data["igmp"]["statistics"].items():
3405 if query == "queryV2":
3406 # Verifying IGMP interface queryV2 statistics
3407 if stats_return:
3408 igmp_stats["statistics"][query] = intf_detail_json[
3409 "queryV2"
3410 ]
3411
3412 else:
3413 if intf_detail_json["queryV2"] != value:
3414 errormsg = (
3415 "[DUT %s]: IGMP interface: %s "
3416 " queryV2 statistics verification "
3417 "[FAILED]!! Expected : %s,"
3418 " Found : %s"
3419 % (
3420 dut,
3421 interface,
3422 value,
3423 intf_detail_json["queryV2"],
3424 )
3425 )
3426 return errormsg
3427
3428 logger.info(
3429 "[DUT %s]: IGMP interface: %s "
3430 "queryV2 statistics is %s",
3431 dut,
3432 interface,
3433 value,
3434 )
3435
3436 if query == "reportV2":
3437 # Verifying IGMP interface timerV2 statistics
3438 if stats_return:
3439 igmp_stats["statistics"][query] = intf_detail_json[
3440 "reportV2"
3441 ]
3442
3443 else:
3444 if intf_detail_json["reportV2"] <= value:
3445 errormsg = (
3446 "[DUT %s]: IGMP reportV2 "
3447 "statistics verification "
3448 "[FAILED]!! Expected : %s "
3449 "or more, Found : %s"
3450 % (
3451 dut,
3452 interface,
3453 value,
e8cd26fd 3454 )
3455 )
3456 return errormsg
3457
3458 logger.info(
3459 "[DUT %s]: IGMP reportV2 " "statistics is %s",
3460 dut,
3461 intf_detail_json["reportV2"],
3462 )
3463
3464 if "query" in data["igmp"]:
3465 for query, value in data["igmp"]["query"].items():
3466 if query == "query-interval":
3467 # Verifying IGMP interface query interval timer
3468 if intf_detail_json["timerQueryInterval"] != value:
3469 errormsg = (
3470 "[DUT %s]: IGMP interface: %s "
3471 " query-interval verification "
3472 "[FAILED]!! Expected : %s,"
3473 " Found : %s"
3474 % (
3475 dut,
3476 interface,
3477 value,
3478 intf_detail_json["timerQueryInterval"],
3479 )
3480 )
3481 return errormsg
3482
3483 logger.info(
3484 "[DUT %s]: IGMP interface: %s " "query-interval is %s",
3485 dut,
3486 interface,
3487 value,
3488 )
3489
3490 if query == "query-max-response-time":
3491 # Verifying IGMP interface query max response timer
3492 if (
3493 intf_detail_json["timerQueryResponseIntervalMsec"]
3494 != value * 100
3495 ):
3496 errormsg = (
3497 "[DUT %s]: IGMP interface: %s "
3498 "query-max-response-time "
3499 "verification [FAILED]!!"
3500 " Expected : %s, Found : %s"
3501 % (
3502 dut,
3503 interface,
3504 value * 1000,
3505 intf_detail_json["timerQueryResponseIntervalMsec"],
3506 )
3507 )
3508 return errormsg
3509
3510 logger.info(
3511 "[DUT %s]: IGMP interface: %s "
3512 "query-max-response-time is %s ms",
3513 dut,
3514 interface,
3515 value * 100,
3516 )
3517
3518 if query == "last-member-query-count":
3519 # Verifying IGMP interface last member query count
3520 if intf_detail_json["lastMemberQueryCount"] != value:
3521 errormsg = (
3522 "[DUT %s]: IGMP interface: %s "
3523 "last-member-query-count "
3524 "verification [FAILED]!!"
3525 " Expected : %s, Found : %s"
3526 % (
3527 dut,
3528 interface,
3529 value,
3530 intf_detail_json["lastMemberQueryCount"],
3531 )
3532 )
3533 return errormsg
3534
3535 logger.info(
3536 "[DUT %s]: IGMP interface: %s "
3537 "last-member-query-count is %s ms",
3538 dut,
3539 interface,
3540 value * 1000,
3541 )
3542
3543 if query == "last-member-query-interval":
3544 # Verifying IGMP interface last member query interval
3545 if (
3546 intf_detail_json["timerLastMemberQueryMsec"]
3547 != value * 100 * intf_detail_json["lastMemberQueryCount"]
3548 ):
3549 errormsg = (
3550 "[DUT %s]: IGMP interface: %s "
3551 "last-member-query-interval "
3552 "verification [FAILED]!!"
3553 " Expected : %s, Found : %s"
3554 % (
3555 dut,
3556 interface,
3557 value * 1000,
3558 intf_detail_json["timerLastMemberQueryMsec"],
3559 )
3560 )
3561 return errormsg
3562
3563 logger.info(
3564 "[DUT %s]: IGMP interface: %s "
3565 "last-member-query-interval is %s ms",
3566 dut,
3567 interface,
3568 value * intf_detail_json["lastMemberQueryCount"] * 100,
3569 )
3570
3571 if "version" in data["igmp"]:
3572 # Verifying IGMP interface state is up
3573 if intf_detail_json["state"] != "up":
3574 errormsg = (
3575 "[DUT %s]: IGMP interface: %s "
3576 " state: %s verification "
3577 "[FAILED]!!" % (dut, interface, intf_detail_json["state"])
3578 )
3579 return errormsg
3580
3581 logger.info(
3582 "[DUT %s]: IGMP interface: %s " "state: %s",
3583 dut,
3584 interface,
3585 intf_detail_json["state"],
3586 )
3587
3588 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3589 return True if stats_return == False else igmp_stats
3590
3591
de3d6b4d 3592@retry(retry_timeout=60, diag_pct=0)
3c41ebf8 3593def verify_pim_config(tgen, input_dict, expected=True):
e8cd26fd 3594 """
3595 Verify pim interface details, verifying following configs:
3596 drPriority
3597 helloPeriod
3598 helloReceived
3599 helloSend
3600 drAddress
3601
3602 Parameters
3603 ----------
3604 * `tgen`: topogen object
3605 * `input_dict` : Input dict data, required to verify
3606 timer
3c41ebf8 3607 * `expected` : expected results from API, by-default True
e8cd26fd 3608
3609 Usage
3610 -----
3611 input_dict ={
3612 "l1": {
3613 "igmp": {
3614 "interfaces": {
3615 "l1-i1-eth1": {
3616 "pim": {
3617 "drPriority" : 10,
3618 "helloPeriod" : 5
3619 }
3620 }
3621 }
3622 }
3623 }
3624 }
3625 }
3626 result = verify_pim_config(tgen, input_dict)
3627
3628 Returns
3629 -------
3630 errormsg(str) or True
3631 """
3632
3633 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3634
3635 for dut in input_dict.keys():
3636 rnode = tgen.routers()[dut]
3637
3638 for interface, data in input_dict[dut]["pim"]["interfaces"].items():
3639
3640 logger.info("[DUT: %s]: Verifying PIM interface %s detail:", dut, interface)
3641
3642 show_ip_igmp_intf_json = run_frr_cmd(
3643 rnode, "show ip pim interface {} json".format(interface), isjson=True
3644 )
3645
3646 if interface not in show_ip_igmp_intf_json:
3647 errormsg = (
3648 "[DUT %s]: PIM interface: %s "
3649 " is not present in CLI output "
3650 "[FAILED]!! " % (dut, interface)
3651 )
3652 return errormsg
3653
3654 intf_detail_json = show_ip_igmp_intf_json[interface]
3655
3656 for config, value in data.items():
3657 if config == "helloPeriod":
3658 # Verifying PIM interface helloPeriod
3659 if intf_detail_json["helloPeriod"] != value:
3660 errormsg = (
3661 "[DUT %s]: PIM interface: %s "
3662 " helloPeriod verification "
3663 "[FAILED]!! Expected : %s,"
3664 " Found : %s"
3665 % (dut, interface, value, intf_detail_json["helloPeriod"])
3666 )
3667 return errormsg
3668
3669 logger.info(
3670 "[DUT %s]: PIM interface: %s " "helloPeriod is %s",
3671 dut,
3672 interface,
3673 value,
3674 )
3675
3676 if config == "drPriority":
3677 # Verifying PIM interface drPriority
3678 if intf_detail_json["drPriority"] != value:
3679 errormsg = (
3680 "[DUT %s]: PIM interface: %s "
3681 " drPriority verification "
3682 "[FAILED]!! Expected : %s,"
3683 " Found : %s"
3684 % (dut, interface, value, intf_detail_json["drPriority"])
3685 )
3686 return errormsg
3687
3688 logger.info(
3689 "[DUT %s]: PIM interface: %s " "drPriority is %s",
3690 dut,
3691 interface,
3692 value,
3693 )
3694
3695 if config == "drAddress":
3696 # Verifying PIM interface drAddress
3697 if intf_detail_json["drAddress"] != value:
3698 errormsg = (
3699 "[DUT %s]: PIM interface: %s "
3700 " drAddress verification "
3701 "[FAILED]!! Expected : %s,"
3702 " Found : %s"
3703 % (dut, interface, value, intf_detail_json["drAddress"])
3704 )
3705 return errormsg
3706
3707 logger.info(
3708 "[DUT %s]: PIM interface: %s " "drAddress is %s",
3709 dut,
3710 interface,
3711 value,
3712 )
3713
3714 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3715 return True
3716
3717
de3d6b4d 3718@retry(retry_timeout=20, diag_pct=0)
3c41ebf8 3719def verify_multicast_traffic(tgen, input_dict, return_traffic=False, expected=True):
e8cd26fd 3720 """
3721 Verify multicast traffic by running
3722 "show multicast traffic count json" cli
3723
3724 Parameters
3725 ----------
3726 * `tgen`: topogen object
3727 * `input_dict(dict)`: defines DUT, what and for which interfaces
3728 traffic needs to be verified
3729 * `return_traffic`: returns traffic stats
3c41ebf8
KK
3730 * `expected` : expected results from API, by-default True
3731
e8cd26fd 3732 Usage
3733 -----
3734 input_dict = {
3735 "r1": {
3736 "traffic_received": ["r1-r0-eth0"],
3737 "traffic_sent": ["r1-r0-eth0"]
3738 }
3739 }
3740
3741 result = verify_multicast_traffic(tgen, input_dict)
3742
3743 Returns
3744 -------
3745 errormsg(str) or True
3746 """
3747
3748 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3749
3750 traffic_dict = {}
3751 for dut in input_dict.keys():
3752 if dut not in tgen.routers():
3753 continue
3754
3755 rnode = tgen.routers()[dut]
3756
3757 logger.info("[DUT: %s]: Verifying multicast " "traffic", dut)
3758
3759 show_multicast_traffic_json = run_frr_cmd(
3760 rnode, "show ip multicast count json", isjson=True
3761 )
3762
3763 for traffic_type, interfaces in input_dict[dut].items():
3764 traffic_dict[traffic_type] = {}
3765 if traffic_type == "traffic_received":
3766 for interface in interfaces:
3767 traffic_dict[traffic_type][interface] = {}
3768 interface_json = show_multicast_traffic_json[interface]
3769
3770 if interface_json["pktsIn"] == 0 and interface_json["bytesIn"] == 0:
3771 errormsg = (
3772 "[DUT %s]: Multicast traffic is "
3773 "not received on interface %s "
3774 "PktsIn: %s, BytesIn: %s "
3775 "[FAILED]!!"
3776 % (
3777 dut,
3778 interface,
3779 interface_json["pktsIn"],
3780 interface_json["bytesIn"],
3781 )
3782 )
3783 return errormsg
3784
3785 elif (
3786 interface_json["pktsIn"] != 0 and interface_json["bytesIn"] != 0
3787 ):
3788
3789 traffic_dict[traffic_type][interface][
3790 "pktsIn"
3791 ] = interface_json["pktsIn"]
3792 traffic_dict[traffic_type][interface][
3793 "bytesIn"
3794 ] = interface_json["bytesIn"]
3795
3796 logger.info(
3797 "[DUT %s]: Multicast traffic is "
3798 "received on interface %s "
3799 "PktsIn: %s, BytesIn: %s "
3800 "[PASSED]!!"
3801 % (
3802 dut,
3803 interface,
3804 interface_json["pktsIn"],
3805 interface_json["bytesIn"],
3806 )
3807 )
3808
3809 else:
3810 errormsg = (
3811 "[DUT %s]: Multicast traffic interface %s:"
3812 " Miss-match in "
3813 "PktsIn: %s, BytesIn: %s"
3814 "[FAILED]!!"
3815 % (
3816 dut,
3817 interface,
3818 interface_json["pktsIn"],
3819 interface_json["bytesIn"],
3820 )
3821 )
3822 return errormsg
3823
3824 if traffic_type == "traffic_sent":
3825 traffic_dict[traffic_type] = {}
3826 for interface in interfaces:
3827 traffic_dict[traffic_type][interface] = {}
3828 interface_json = show_multicast_traffic_json[interface]
3829
3830 if (
3831 interface_json["pktsOut"] == 0
3832 and interface_json["bytesOut"] == 0
3833 ):
3834 errormsg = (
3835 "[DUT %s]: Multicast traffic is "
3836 "not received on interface %s "
3837 "PktsIn: %s, BytesIn: %s"
3838 "[FAILED]!!"
3839 % (
3840 dut,
3841 interface,
3842 interface_json["pktsOut"],
3843 interface_json["bytesOut"],
3844 )
3845 )
3846 return errormsg
3847
3848 elif (
3849 interface_json["pktsOut"] != 0
3850 and interface_json["bytesOut"] != 0
3851 ):
3852
3853 traffic_dict[traffic_type][interface][
3854 "pktsOut"
3855 ] = interface_json["pktsOut"]
3856 traffic_dict[traffic_type][interface][
3857 "bytesOut"
3858 ] = interface_json["bytesOut"]
3859
3860 logger.info(
3861 "[DUT %s]: Multicast traffic is "
3862 "received on interface %s "
3863 "PktsOut: %s, BytesOut: %s "
3864 "[PASSED]!!"
3865 % (
3866 dut,
3867 interface,
3868 interface_json["pktsOut"],
3869 interface_json["bytesOut"],
3870 )
3871 )
3872 else:
3873 errormsg = (
3874 "[DUT %s]: Multicast traffic interface %s:"
3875 " Miss-match in "
3876 "PktsOut: %s, BytesOut: %s "
3877 "[FAILED]!!"
3878 % (
3879 dut,
3880 interface,
3881 interface_json["pktsOut"],
3882 interface_json["bytesOut"],
3883 )
3884 )
3885 return errormsg
3886
3887 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3888 return True if return_traffic == False else traffic_dict
3889
3890
3891def get_refCount_for_mroute(tgen, dut, iif, src_address, group_addresses):
3892 """
3893 Verify upstream inbound interface is updated correctly
3894 by running "show ip pim upstream" cli
3895
3896 Parameters
3897 ----------
3898 * `tgen`: topogen object
3899 * `dut`: device under test
3900 * `iif`: inbound interface
3901 * `src_address`: source address
3902 * `group_addresses`: IGMP group address
3903
3904 Usage
3905 -----
3906 dut = "r1"
3907 iif = "r1-r0-eth0"
3908 src_address = "*"
3909 group_address = "225.1.1.1"
3910 result = get_refCount_for_mroute(tgen, dut, iif, src_address,
3911 group_address)
3912
3913 Returns
3914 -------
3915 refCount(int)
3916 """
3917
3918 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3919
3920 refCount = 0
3921 if dut not in tgen.routers():
3922 return False
3923
3924 rnode = tgen.routers()[dut]
3925
3926 logger.info("[DUT: %s]: Verifying refCount for mroutes: ", dut)
3927 show_ip_pim_upstream_json = run_frr_cmd(
3928 rnode, "show ip pim upstream json", isjson=True
3929 )
3930
3931 if type(group_addresses) is not list:
3932 group_addresses = [group_addresses]
3933
3934 for grp_addr in group_addresses:
3935 # Verify group address
3936 if grp_addr not in show_ip_pim_upstream_json:
3937 errormsg = "[DUT %s]: Verifying upstream" " for group %s [FAILED]!!" % (
3938 dut,
3939 grp_addr,
3940 )
3941 return errormsg
3942 group_addr_json = show_ip_pim_upstream_json[grp_addr]
3943
3944 # Verify source address
3945 if src_address not in group_addr_json:
3946 errormsg = "[DUT %s]: Verifying upstream" " for (%s,%s) [FAILED]!!" % (
3947 dut,
3948 src_address,
3949 grp_addr,
3950 )
3951 return errormsg
3952
3953 # Verify Inbound Interface
3954 if group_addr_json[src_address]["inboundInterface"] == iif:
3955 refCount = group_addr_json[src_address]["refCount"]
3956
3957 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
3958 return refCount
3959
3960
de3d6b4d 3961@retry(retry_timeout=40, diag_pct=0)
a53c08bc
CH
3962def verify_multicast_flag_state(
3963 tgen, dut, src_address, group_addresses, flag, expected=True
3964):
e8cd26fd 3965 """
3966 Verify flag state for mroutes and make sure (*, G)/(S, G) are having
3967 coorect flags by running "show ip mroute" cli
3968
3969 Parameters
3970 ----------
3971 * `tgen`: topogen object
3972 * `dut`: device under test
3973 * `src_address`: source address
3974 * `group_addresses`: IGMP group address
3975 * `flag`: flag state, needs to be verified
3c41ebf8 3976 * `expected` : expected results from API, by-default True
e8cd26fd 3977
3978 Usage
3979 -----
3980 dut = "r1"
3981 flag = "SC"
3982 group_address = "225.1.1.1"
3983 result = verify_multicast_flag_state(tgen, dut, src_address,
3984 group_address, flag)
3985
3986 Returns
3987 -------
3988 errormsg(str) or True
3989 """
3990
3991 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
3992
3993 if dut not in tgen.routers():
3994 return False
3995
3996 rnode = tgen.routers()[dut]
3997
3998 logger.info("[DUT: %s]: Verifying flag state for mroutes", dut)
3999 show_ip_mroute_json = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
4000
4001 if bool(show_ip_mroute_json) == False:
4002 error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
4003 return error_msg
4004
4005 if type(group_addresses) is not list:
4006 group_addresses = [group_addresses]
4007
4008 for grp_addr in group_addresses:
4009 if grp_addr not in show_ip_mroute_json:
4010 errormsg = (
4011 "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! ",
4012 dut,
4013 src_address,
4014 grp_addr,
4015 )
4016 return errormsg
4017 else:
4018 group_addr_json = show_ip_mroute_json[grp_addr]
4019
4020 if src_address not in group_addr_json:
4021 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
4022 dut,
4023 src_address,
4024 grp_addr,
4025 )
4026 return errormsg
4027 else:
4028 mroutes = group_addr_json[src_address]
4029
4030 if mroutes["installed"] != 0:
4031 logger.info(
4032 "[DUT %s]: mroute (%s,%s) is installed", dut, src_address, grp_addr
4033 )
4034
4035 if mroutes["flags"] != flag:
4036 errormsg = (
4037 "[DUT %s]: Verifying flag for (%s, %s) "
4038 "mroute [FAILED]!! "
4039 "Expected: %s Found: %s"
4040 % (dut, src_address, grp_addr, flag, mroutes["flags"])
4041 )
4042 return errormsg
4043
4044 logger.info(
4045 "[DUT %s]: Verifying flag for (%s, %s)"
4046 " mroute, [PASSED]!! "
4047 "Found Expected: %s",
4048 dut,
4049 src_address,
4050 grp_addr,
4051 mroutes["flags"],
4052 )
4053
4054 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4055 return True
eab72dc8 4056
4057
de3d6b4d 4058@retry(retry_timeout=40, diag_pct=0)
d7032129 4059def verify_igmp_interface(tgen, dut, igmp_iface, interface_ip, expected=True):
eab72dc8 4060 """
4061 Verify all IGMP interface are up and running, config is verified
4062 using "show ip igmp interface" cli
4063
4064 Parameters
4065 ----------
4066 * `tgen`: topogen object
4067 * `topo` : json file data
4068 * `dut` : device under test
4069 * `igmp_iface` : interface name
4070 * `interface_ip` : interface ip address
3c41ebf8 4071 * `expected` : expected results from API, by-default True
eab72dc8 4072
4073 Usage
4074 -----
4075 result = verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip)
4076
4077 Returns
4078 -------
4079 errormsg(str) or True
4080 """
4081
4082 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4083
4084 for router in tgen.routers():
4085 if router != dut:
4086 continue
4087
5980ad0a 4088 logger.info("[DUT: %s]: Verifying PIM interface status:", dut)
eab72dc8 4089
4090 rnode = tgen.routers()[dut]
5980ad0a
DS
4091 show_ip_igmp_interface_json = run_frr_cmd(
4092 rnode, "show ip igmp interface json", isjson=True
4093 )
eab72dc8 4094
5980ad0a 4095 if igmp_iface in show_ip_igmp_interface_json:
eab72dc8 4096 igmp_intf_json = show_ip_igmp_interface_json[igmp_iface]
4097 # Verifying igmp interface
5980ad0a
DS
4098 if igmp_intf_json["address"] != interface_ip:
4099 errormsg = (
4100 "[DUT %s]: igmp interface ip is not correct "
4101 "[FAILED]!! Expected : %s, Found : %s"
4102 % (dut, igmp_intf_json["address"], interface_ip)
4103 )
eab72dc8 4104 return errormsg
4105
5980ad0a
DS
4106 logger.info(
4107 "[DUT %s]: igmp interface: %s, " "interface ip: %s" " [PASSED]!!",
4108 dut,
4109 igmp_iface,
4110 interface_ip,
4111 )
eab72dc8 4112 else:
5980ad0a
DS
4113 errormsg = (
4114 "[DUT %s]: igmp interface: %s "
4115 "igmp interface ip: %s, is not present "
4116 % (dut, igmp_iface, interface_ip)
4117 )
eab72dc8 4118 return errormsg
4119
4120 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4121 return True
a5124c49
CH
4122
4123
a53c08bc 4124class McastTesterHelper(HostApplicationHelper):
a5124c49
CH
4125 def __init__(self, tgen=None):
4126 self.script_path = os.path.join(CWD, "mcast-tester.py")
4127 self.host_conn = {}
4128 self.listen_sock = None
4129
4130 # # Get a temporary file for socket path
4131 # (fd, sock_path) = tempfile.mkstemp("-mct.sock", "tmp" + str(os.getpid()))
4132 # os.close(fd)
4133 # os.remove(sock_path)
4134 # self.app_sock_path = sock_path
4135
4136 # # Listen on unix socket
4137 # logger.debug("%s: listening on socket %s", self, self.app_sock_path)
4138 # self.listen_sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
4139 # self.listen_sock.settimeout(10)
4140 # self.listen_sock.bind(self.app_sock_path)
4141 # self.listen_sock.listen(10)
4142
4143 python3_path = get_exec_path(["python3", "python"])
4144 super(McastTesterHelper, self).__init__(
4145 tgen,
4146 # [python3_path, self.script_path, self.app_sock_path]
a53c08bc 4147 [python3_path, self.script_path],
a5124c49
CH
4148 )
4149
a53c08bc 4150 def __str__(self):
a5124c49
CH
4151 return "McastTesterHelper({})".format(self.script_path)
4152
4153 def run_join(self, host, join_addrs, join_towards=None, join_intf=None):
4154 """
4155 Join a UDP multicast group.
4156
4157 One of join_towards or join_intf MUST be set.
4158
4159 Parameters:
4160 -----------
4161 * `host`: host from where IGMP join would be sent
4162 * `join_addrs`: multicast address (or addresses) to join to
4163 * `join_intf`: the interface to bind the join[s] to
4164 * `join_towards`: router whos interface to bind the join[s] to
4165 """
4166 if not isinstance(join_addrs, list) and not isinstance(join_addrs, tuple):
4167 join_addrs = [join_addrs]
4168
4169 if join_towards:
a53c08bc
CH
4170 join_intf = frr_unicode(
4171 self.tgen.json_topo["routers"][host]["links"][join_towards]["interface"]
4172 )
a5124c49
CH
4173 else:
4174 assert join_intf
4175
4176 for join in join_addrs:
4177 self.run(host, [join, join_intf])
4178
4179 return True
4180
4181 def run_traffic(self, host, send_to_addrs, bind_towards=None, bind_intf=None):
4182 """
4183 Send UDP multicast traffic.
4184
4185 One of bind_towards or bind_intf MUST be set.
4186
4187 Parameters:
4188 -----------
4189 * `host`: host to send traffic from
4190 * `send_to_addrs`: multicast address (or addresses) to send traffic to
4191 * `bind_towards`: Router who's interface the source ip address is got from
4192 """
4193 if bind_towards:
a53c08bc
CH
4194 bind_intf = frr_unicode(
4195 self.tgen.json_topo["routers"][host]["links"][bind_towards]["interface"]
4196 )
a5124c49
CH
4197 else:
4198 assert bind_intf
4199
4200 if not isinstance(send_to_addrs, list) and not isinstance(send_to_addrs, tuple):
4201 send_to_addrs = [send_to_addrs]
4202
4203 for send_to in send_to_addrs:
4204 self.run(host, ["--send=0.7", send_to, bind_intf])
4205
4206 return True
4207
c28e6ef5 4208
e46ce55e
KK
4209@retry(retry_timeout=62)
4210def verify_local_igmp_groups(tgen, dut, interface, group_addresses):
4211 """
4212 Verify local IGMP groups are received from an intended interface
4213 by running "show ip igmp join json" command
4214
4215 Parameters
4216 ----------
4217 * `tgen`: topogen object
4218 * `dut`: device under test
4219 * `interface`: interface, from which IGMP groups are configured
4220 * `group_addresses`: IGMP group address
4221
4222 Usage
4223 -----
4224 dut = "r1"
4225 interface = "r1-r0-eth0"
4226 group_address = "225.1.1.1"
4227 result = verify_local_igmp_groups(tgen, dut, interface, group_address)
4228
4229 Returns
4230 -------
4231 errormsg(str) or True
4232 """
4233
4234 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4235
4236 if dut not in tgen.routers():
4237 return False
4238
4239 rnode = tgen.routers()[dut]
4240
4241 logger.info("[DUT: %s]: Verifying local IGMP groups received:", dut)
4242 show_ip_local_igmp_json = run_frr_cmd(rnode, "show ip igmp join json", isjson=True)
4243
4244 if type(group_addresses) is not list:
4245 group_addresses = [group_addresses]
4246
4247 if interface not in show_ip_local_igmp_json:
4248
4249 errormsg = (
4250 "[DUT %s]: Verifying local IGMP group received"
4251 " from interface %s [FAILED]!! " % (dut, interface)
4252 )
4253 return errormsg
4254
4255 for grp_addr in group_addresses:
4256 found = False
4257 for index in show_ip_local_igmp_json[interface]["groups"]:
4258 if index["group"] == grp_addr:
4259 found = True
4260 break
4261 if not found:
4262 errormsg = (
4263 "[DUT %s]: Verifying local IGMP group received"
4264 " from interface %s [FAILED]!! "
4265 " Expected: %s " % (dut, interface, grp_addr)
4266 )
4267 return errormsg
4268
4269 logger.info(
4270 "[DUT %s]: Verifying local IGMP group %s received "
4271 "from interface %s [PASSED]!! ",
4272 dut,
4273 grp_addr,
4274 interface,
4275 )
4276
4277 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4278 return True
4279
4280
e13f9c4f 4281def verify_pim_interface_traffic(tgen, input_dict, return_stats=True, addr_type="ipv4"):
c28e6ef5 4282 """
d7032129 4283 Verify ip pim interface traffic by running
c28e6ef5 4284 "show ip pim interface traffic" cli
4285
4286 Parameters
4287 ----------
4288 * `tgen`: topogen object
4289 * `input_dict(dict)`: defines DUT, what and from which interfaces
4290 traffic needs to be verified
e13f9c4f
KK
4291 * [optional]`addr_type`: specify address-family, default is ipv4
4292
c28e6ef5 4293 Usage
4294 -----
4295 input_dict = {
4296 "r1": {
4297 "r1-r0-eth0": {
4298 "helloRx": 0,
4299 "helloTx": 1,
4300 "joinRx": 0,
4301 "joinTx": 0
4302 }
4303 }
4304 }
4305
4306 result = verify_pim_interface_traffic(tgen, input_dict)
4307
4308 Returns
4309 -------
4310 errormsg(str) or True
4311 """
4312
4313 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4314
4315 output_dict = {}
4316 for dut in input_dict.keys():
4317 if dut not in tgen.routers():
4318 continue
4319
4320 rnode = tgen.routers()[dut]
4321
4322 logger.info("[DUT: %s]: Verifying pim interface traffic", dut)
e13f9c4f
KK
4323
4324 if addr_type == "ipv4":
4325 cmd = "show ip pim interface traffic json"
4326 elif addr_type == "ipv6":
4327 cmd = "show ipv6 pim interface traffic json"
4328
4329 show_pim_intf_traffic_json = run_frr_cmd(rnode, cmd, isjson=True)
c28e6ef5 4330
4331 output_dict[dut] = {}
4332 for intf, data in input_dict[dut].items():
4333 interface_json = show_pim_intf_traffic_json[intf]
4334 for state in data:
4335
4336 # Verify Tx/Rx
4337 if state in interface_json:
4338 output_dict[dut][state] = interface_json[state]
4339 else:
4340 errormsg = (
4341 "[DUT %s]: %s is not present"
4342 "for interface %s [FAILED]!! " % (dut, state, intf)
4343 )
4344 return errormsg
4345
4346 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4347 return True if return_stats == False else output_dict
4348
d7032129
KK
4349
4350@retry(retry_timeout=40, diag_pct=0)
4351def verify_mld_groups(tgen, dut, interface, group_addresses, expected=True):
4352 """
4353 Verify IGMP groups are received from an intended interface
4354 by running "show ip mld groups" command
4355
4356 Parameters
4357 ----------
4358 * `tgen`: topogen object
4359 * `dut`: device under test
4360 * `interface`: interface, from which MLD groups would be received
4361 * `group_addresses`: MLD group address
4362 * `expected` : expected results from API, by-default True
4363
4364 Usage
4365 -----
4366 dut = "r1"
4367 interface = "r1-r0-eth0"
4368 group_address = "ffaa::1"
4369 result = verify_mld_groups(tgen, dut, interface, group_address)
4370
4371 Returns
4372 -------
4373 errormsg(str) or True
4374 """
4375
4376 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4377
4378 if dut not in tgen.routers():
4379 return False
4380
4381 rnode = tgen.routers()[dut]
4382
4383 logger.info("[DUT: %s]: Verifying mld groups received:", dut)
4384 show_mld_json = run_frr_cmd(rnode, "show ipv6 mld groups json", isjson=True)
4385
4386 if type(group_addresses) is not list:
4387 group_addresses = [group_addresses]
4388
4389 if interface in show_mld_json:
4390 show_mld_json = show_mld_json[interface]["groups"]
4391 else:
4392 errormsg = (
4393 "[DUT %s]: Verifying MLD group received"
4394 " from interface %s [FAILED]!! " % (dut, interface)
4395 )
4396 return errormsg
4397
4398 found = False
4399 for grp_addr in group_addresses:
4400 for index in show_mld_json:
4401 if index["group"] == grp_addr:
4402 found = True
4403 break
4404 if found is not True:
4405 errormsg = (
4406 "[DUT %s]: Verifying MLD group received"
4407 " from interface %s [FAILED]!! "
4408 " Expected not found: %s" % (dut, interface, grp_addr)
4409 )
4410 return errormsg
4411
4412 logger.info(
4413 "[DUT %s]: Verifying MLD group %s received "
4414 "from interface %s [PASSED]!! ",
4415 dut,
4416 grp_addr,
4417 interface,
4418 )
4419
4420 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4421 return True
4422
4423
4424@retry(retry_timeout=40, diag_pct=0)
4425def verify_mld_interface(tgen, dut, mld_iface, interface_ip, expected=True):
4426 """
4427 Verify all IGMP interface are up and running, config is verified
4428 using "show ip mld interface" cli
4429
4430 Parameters
4431 ----------
4432 * `tgen`: topogen object
4433 * `topo` : json file data
4434 * `dut` : device under test
4435 * `mld_iface` : interface name
4436 * `interface_ip` : interface ip address
4437 * `expected` : expected results from API, by-default True
4438
4439 Usage
4440 -----
4441 result = verify_mld_interface(tgen, topo, dut, mld_iface, interface_ip)
4442
4443 Returns
4444 -------
4445 errormsg(str) or True
4446 """
4447
4448 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4449
4450 for router in tgen.routers():
4451 if router != dut:
4452 continue
4453
4454 logger.info("[DUT: %s]: Verifying MLD interface status:", dut)
4455
4456 rnode = tgen.routers()[dut]
4457 show_mld_interface_json = run_frr_cmd(
4458 rnode, "show ipv6 mld interface json", isjson=True
4459 )
4460
4461 if mld_iface in show_mld_interface_json:
4462 mld_intf_json = show_mld_interface_json[mld_iface]
4463 # Verifying igmp interface
4464 if mld_intf_json["address"] != interface_ip:
4465 errormsg = (
4466 "[DUT %s]: igmp interface ip is not correct "
4467 "[FAILED]!! Expected : %s, Found : %s"
4468 % (dut, mld_intf_json["address"], interface_ip)
4469 )
4470 return errormsg
4471
4472 logger.info(
4473 "[DUT %s]: igmp interface: %s, " "interface ip: %s" " [PASSED]!!",
4474 dut,
4475 mld_iface,
4476 interface_ip,
4477 )
4478 else:
4479 errormsg = (
4480 "[DUT %s]: igmp interface: %s "
4481 "igmp interface ip: %s, is not present "
4482 % (dut, mld_iface, interface_ip)
4483 )
4484 return errormsg
4485
4486 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4487 return True
4488
4489
4490@retry(retry_timeout=60, diag_pct=0)
4491def verify_mld_config(tgen, input_dict, stats_return=False, expected=True):
4492 """
4493 Verify mld interface details, verifying following configs:
4494 timerQueryInterval
4495 timerQueryResponseIntervalMsec
4496 lastMemberQueryCount
4497 timerLastMemberQueryMsec
4498
4499 Parameters
4500 ----------
4501 * `tgen`: topogen object
4502 * `input_dict` : Input dict data, required to verify
4503 timer
4504 * `stats_return`: If user wants API to return statistics
4505 * `expected` : expected results from API, by-default True
4506
4507 Usage
4508 -----
4509 input_dict ={
4510 "l1": {
4511 "mld": {
4512 "interfaces": {
4513 "l1-i1-eth1": {
4514 "mld": {
4515 "query": {
4516 "query-interval" : 200,
4517 "query-max-response-time" : 100
4518 },
4519 "statistics": {
4520 "queryV2" : 2,
4521 "reportV2" : 1
4522 }
4523 }
4524 }
4525 }
4526 }
4527 }
4528 }
4529 result = verify_mld_config(tgen, input_dict, stats_return)
4530
4531 Returns
4532 -------
4533 errormsg(str) or True
4534 """
4535
4536 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4537
4538 for dut in input_dict.keys():
4539 rnode = tgen.routers()[dut]
4540
4541 for interface, data in input_dict[dut]["igmp"]["interfaces"].items():
4542
4543 statistics = False
4544 report = False
4545 if "statistics" in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"]:
4546 statistics = True
4547 cmd = "show ipv6 mld statistics"
4548 else:
4549 cmd = "show ipv6 mld"
4550
4551 logger.info("[DUT: %s]: Verifying MLD interface %s detail:", dut, interface)
4552
4553 if statistics:
4554 if (
4555 "report"
4556 in input_dict[dut]["mld"]["interfaces"][interface]["mld"][
4557 "statistics"
4558 ]
4559 ):
4560 report = True
4561
4562 if statistics and report:
4563 show_ipv6_mld_intf_json = run_frr_cmd(
4564 rnode, "{} json".format(cmd), isjson=True
4565 )
4566 intf_detail_json = show_ipv6_mld_intf_json["global"]
4567 else:
4568 show_ipv6_mld_intf_json = run_frr_cmd(
4569 rnode, "{} interface {} json".format(cmd, interface), isjson=True
4570 )
4571
4572 if not report:
4573 if interface not in show_ipv6_mld_intf_json:
4574 errormsg = (
4575 "[DUT %s]: MLD interface: %s "
4576 " is not present in CLI output "
4577 "[FAILED]!! " % (dut, interface)
4578 )
4579 return errormsg
4580
4581 else:
4582 intf_detail_json = show_ipv6_mld_intf_json[interface]
4583
4584 if stats_return:
4585 mld_stats = {}
4586
4587 if "statistics" in data["mld"]:
4588 if stats_return:
4589 mld_stats["statistics"] = {}
4590 for query, value in data["mld"]["statistics"].items():
4591 if query == "queryV1":
4592 # Verifying IGMP interface queryV2 statistics
4593 if stats_return:
4594 mld_stats["statistics"][query] = intf_detail_json["queryV1"]
4595
4596 else:
4597 if intf_detail_json["queryV1"] != value:
4598 errormsg = (
4599 "[DUT %s]: MLD interface: %s "
4600 " queryV1 statistics verification "
4601 "[FAILED]!! Expected : %s,"
4602 " Found : %s"
4603 % (
4604 dut,
4605 interface,
4606 value,
4607 intf_detail_json["queryV1"],
4608 )
4609 )
4610 return errormsg
4611
4612 logger.info(
4613 "[DUT %s]: MLD interface: %s "
4614 "queryV1 statistics is %s",
4615 dut,
4616 interface,
4617 value,
4618 )
4619
4620 if query == "reportV1":
4621 # Verifying IGMP interface timerV2 statistics
4622 if stats_return:
4623 mld_stats["statistics"][query] = intf_detail_json[
4624 "reportV1"
4625 ]
4626
4627 else:
4628 if intf_detail_json["reportV1"] <= value:
4629 errormsg = (
4630 "[DUT %s]: MLD reportV1 "
4631 "statistics verification "
4632 "[FAILED]!! Expected : %s "
4633 "or more, Found : %s"
4634 % (
4635 dut,
4636 interface,
4637 value,
4638 )
4639 )
4640 return errormsg
4641
4642 logger.info(
4643 "[DUT %s]: MLD reportV1 " "statistics is %s",
4644 dut,
4645 intf_detail_json["reportV1"],
4646 )
4647
4648 if "query" in data["mld"]:
4649 for query, value in data["mld"]["query"].items():
4650 if query == "query-interval":
4651 # Verifying IGMP interface query interval timer
4652 if intf_detail_json["timerQueryInterval"] != value:
4653 errormsg = (
4654 "[DUT %s]: MLD interface: %s "
4655 " query-interval verification "
4656 "[FAILED]!! Expected : %s,"
4657 " Found : %s"
4658 % (
4659 dut,
4660 interface,
4661 value,
4662 intf_detail_json["timerQueryInterval"],
4663 )
4664 )
4665 return errormsg
4666
4667 logger.info(
4668 "[DUT %s]: MLD interface: %s " "query-interval is %s",
4669 dut,
4670 interface,
4671 value,
4672 )
4673
4674 if query == "query-max-response-time":
4675 # Verifying IGMP interface query max response timer
4676 if (
4677 intf_detail_json["timerQueryResponseIntervalMsec"]
4678 != value * 100
4679 ):
4680 errormsg = (
4681 "[DUT %s]: MLD interface: %s "
4682 "query-max-response-time "
4683 "verification [FAILED]!!"
4684 " Expected : %s, Found : %s"
4685 % (
4686 dut,
4687 interface,
4688 value * 1000,
4689 intf_detail_json["timerQueryResponseIntervalMsec"],
4690 )
4691 )
4692 return errormsg
4693
4694 logger.info(
4695 "[DUT %s]: MLD interface: %s "
4696 "query-max-response-time is %s ms",
4697 dut,
4698 interface,
4699 value * 100,
4700 )
4701
4702 if query == "last-member-query-count":
4703 # Verifying IGMP interface last member query count
4704 if intf_detail_json["lastMemberQueryCount"] != value:
4705 errormsg = (
4706 "[DUT %s]: MLD interface: %s "
4707 "last-member-query-count "
4708 "verification [FAILED]!!"
4709 " Expected : %s, Found : %s"
4710 % (
4711 dut,
4712 interface,
4713 value,
4714 intf_detail_json["lastMemberQueryCount"],
4715 )
4716 )
4717 return errormsg
4718
4719 logger.info(
4720 "[DUT %s]: MLD interface: %s "
4721 "last-member-query-count is %s ms",
4722 dut,
4723 interface,
4724 value * 1000,
4725 )
4726
4727 if query == "last-member-query-interval":
4728 # Verifying IGMP interface last member query interval
4729 if (
4730 intf_detail_json["timerLastMemberQueryMsec"]
4731 != value * 100 * intf_detail_json["lastMemberQueryCount"]
4732 ):
4733 errormsg = (
4734 "[DUT %s]: MLD interface: %s "
4735 "last-member-query-interval "
4736 "verification [FAILED]!!"
4737 " Expected : %s, Found : %s"
4738 % (
4739 dut,
4740 interface,
4741 value * 1000,
4742 intf_detail_json["timerLastMemberQueryMsec"],
4743 )
4744 )
4745 return errormsg
4746
4747 logger.info(
4748 "[DUT %s]: MLD interface: %s "
4749 "last-member-query-interval is %s ms",
4750 dut,
4751 interface,
4752 value * intf_detail_json["lastMemberQueryCount"] * 100,
4753 )
4754
4755 if "version" in data["mld"]:
4756 # Verifying IGMP interface state is up
4757 if intf_detail_json["state"] != "up":
4758 errormsg = (
4759 "[DUT %s]: MLD interface: %s "
4760 " state: %s verification "
4761 "[FAILED]!!" % (dut, interface, intf_detail_json["state"])
4762 )
4763 return errormsg
4764
4765 logger.info(
4766 "[DUT %s]: MLD interface: %s " "state: %s",
4767 dut,
4768 interface,
4769 intf_detail_json["state"],
4770 )
4771
4772 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4773 return True if stats_return == False else mld_stats
4774
4775
4776@retry(retry_timeout=60, diag_pct=0)
4777def verify_pim_nexthop(tgen, topo, dut, nexthop, addr_type):
4778 """
4779 Verify all PIM nexthop details using "show ip/ipv6 pim neighbor" cli
4780
4781 Parameters
4782 ----------
4783 * `tgen`: topogen object
4784 * `topo` : json file data
4785 * `dut` : dut info
4786 * `nexthop` : nexthop ip/ipv6 address
4787
4788 Usage
4789 -----
4790 result = verify_pim_nexthop(tgen, topo, dut, nexthop)
4791
4792 Returns
4793 -------
4794 errormsg(str) or True
4795 """
4796 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4797
4798 rnode = tgen.routers()[dut]
4799
4800 if addr_type == "ipv4":
4801 ip_cmd = "ip"
4802 elif addr_type == "ipv6":
4803 ip_cmd = "ipv6"
4804
4805 cmd = "show {} pim nexthop".format(addr_type)
4806 pim_nexthop = rnode.vtysh_cmd(cmd)
4807
4808 if nexthop in pim_nexthop:
4809 logger.info("[DUT %s]: Expected nexthop: %s, Found", dut, nexthop)
4810 return True
4811 else:
4812 errormsg = "[DUT %s]: Nexthop not found: %s" % (dut, nexthop)
4813 return errormsg
4814
4815 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4816 return True
4817
4818
4819@retry(retry_timeout=60, diag_pct=0)
4820def verify_mroute_summary(
4821 tgen, dut, sg_mroute=None, starg_mroute=None, total_mroute=None, addr_type="ipv4"
4822):
4823 """
4824 Verify ip mroute summary has correct (*,g) (s,G) and total mroutes
4825 by running "show ip mroutes summary json" cli
4826
4827 Parameters
4828 ----------
4829 * `tgen`: topogen object
4830 * `dut`: device under test
4831 * `sg_mroute`: Number of installed (s,g) mroute
4832 * `starg_mroute`: Number installed of (*,g) mroute
4833 * `Total_mroute`: Total number of installed mroutes
4834 * 'addr_type : IPv4 or IPv6 address
4835 * `return_json`: Whether to return raw json data
4836
4837 Usage
4838 -----
4839 dut = "r1"
4840 sg_mroute = "4000"
4841 starg_mroute= "2000"
4842 total_mroute = "6000"
4843 addr_type=IPv4 or IPv6
4844 result = verify_mroute_summary(tgen, dut, sg_mroute=None, starg_mroute=None,
4845 total_mroute= None)
4846 Returns
4847 -------
4848 errormsg or True
4849 """
4850
4851 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4852
4853 if dut not in tgen.routers():
4854 return False
4855
4856 rnode = tgen.routers()[dut]
4857
4858 logger.info("[DUT: %s]: Verifying mroute summary", dut)
4859
4860 if addr_type == "ipv4":
4861 ip_cmd = "ip"
4862 elif addr_type == "ipv6":
4863 ip_cmd = "ipv6"
4864
4865 cmd = "show {} mroute summary json".format(ip_cmd)
4866 show_mroute_summary_json = run_frr_cmd(rnode, cmd, isjson=True)
4867
4868 if starg_mroute is not None:
4869 if show_mroute_summary_json["wildcardGroup"]["installed"] != starg_mroute:
4870 logger.error(
4871 "Number of installed starg are: %s but expected: %s",
4872 show_mroute_summary_json["wildcardGroup"]["installed"],
4873 starg_mroute,
4874 )
4875 return False
4876 logger.info(
4877 "Number of installed starg routes are %s",
4878 show_mroute_summary_json["wildcardGroup"]["installed"],
4879 )
4880
4881 if sg_mroute is not None:
4882 if show_mroute_summary_json["sourceGroup"]["installed"] != sg_mroute:
4883 logger.error(
4884 "Number of installed SG routes are: %s but expected: %s",
4885 show_mroute_summary_json["sourceGroup"]["installed"],
4886 sg_mroute,
4887 )
4888 return False
4889 logger.info(
4890 "Number of installed SG routes are %s",
4891 show_mroute_summary_json["sourceGroup"]["installed"],
4892 )
4893
4894 if total_mroute is not None:
4895 if show_mroute_summary_json["totalNumOfInstalledMroutes"] != total_mroute:
4896 logger.error(
4897 "Total number of installed mroutes are: %s but expected: %s",
4898 show_mroute_summary_json["totalNumOfInstalledMroutes"],
4899 total_mroute,
4900 )
4901 return False
4902 logger.info(
4903 "Number of installed Total mroute are %s",
4904 show_mroute_summary_json["totalNumOfInstalledMroutes"],
4905 )
4906
4907 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4908 return True
4909
4910
4911def verify_sg_traffic(tgen, dut, groups, src, addr_type="ipv4"):
4912 """
4913 Verify multicast traffic by running
4914 "show ip mroute count json" cli
4915
4916 Parameters
4917 ----------
4918 * `tgen`: topogen object
4919 * `groups`: igmp or mld groups where traffic needs to be verified
4920
4921 Usage
4922 -----
4923 result = verify_sg_traffic(tgen, "r1", igmp_groups, srcaddress)
4924
4925 Returns
4926 -------
4927 errormsg(str) or True
4928 """
4929
4930 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4931 result = False
4932
4933 rnode = tgen.routers()[dut]
4934
4935 logger.info("[DUT: %s]: Verifying multicast " "SG traffic", dut)
4936
4937 if addr_type == "ipv4":
4938 cmd = "show ip mroute count json"
4939 elif addr_type == "ipv6":
4940 cmd = "show ipv6 mroute count json"
4941 # import pdb; pdb.set_trace()
4942 show_mroute_sg_traffic_json = run_frr_cmd(rnode, cmd, isjson=True)
4943
4944 if bool(show_mroute_sg_traffic_json) is False:
4945 errormsg = "[DUT %s]: Json output is empty" % (dut)
4946 return errormsg
4947
4948 before_traffic = {}
4949 after_traffic = {}
4950
4951 for grp in groups:
4952 if grp not in show_mroute_sg_traffic_json:
4953 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
4954 dut,
4955 src,
4956 grp,
4957 )
4958 if src not in show_mroute_sg_traffic_json[grp]:
4959 errormsg = (
4960 "[DUT %s]: Verifying source is not present in "
4961 " %s [FAILED]!! " % (dut, src)
4962 )
4963 return errormsg
4964
4965 before_traffic[grp] = show_mroute_sg_traffic_json[grp][src]["packets"]
4966
4967 logger.info("Waiting for 10sec traffic to increament")
4968 sleep(10)
4969
4970 show_mroute_sg_traffic_json = run_frr_cmd(rnode, cmd, isjson=True)
4971
4972 for grp in groups:
4973 if grp not in show_mroute_sg_traffic_json:
4974 errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
4975 dut,
4976 src,
4977 grp,
4978 )
4979 if src not in show_mroute_sg_traffic_json[grp]:
4980 errormsg = (
4981 "[DUT %s]: Verifying source is not present in "
4982 " %s [FAILED]!! " % (dut, src)
4983 )
4984 return errormsg
4985
4986 after_traffic[grp] = show_mroute_sg_traffic_json[grp][src]["packets"]
4987
4988 for grp in groups:
4989 if after_traffic[grp] < before_traffic[grp]:
4990 errormsg = (
4991 "[DUT %s]: Verifying igmp group %s source %s not increamenting traffic"
4992 " [FAILED]!! " % (dut, grp, src)
4993 )
4994 return errormsg
4995 else:
4996 logger.info(
4997 "[DUT %s]:igmp group %s source %s receiving traffic"
4998 " [PASSED]!! " % (dut, grp, src)
4999 )
5000 result = True
5001
5002 return result
5003
a5124c49
CH
5004 # def cleanup(self):
5005 # super(McastTesterHelper, self).cleanup()
5006
5007 # if not self.listen_sock:
5008 # return
5009
5010 # logger.debug("%s: closing listen socket %s", self, self.app_sock_path)
5011 # self.listen_sock.close()
5012 # self.listen_sock = None
5013
5014 # if os.path.exists(self.app_sock_path):
5015 # os.remove(self.app_sock_path)
5016
5017 # def started_proc(self, host, p):
5018 # logger.debug("%s: %s: accepting on socket %s", self, host, self.app_sock_path)
5019 # try:
5020 # conn = self.listen_sock.accept()
5021 # return conn
5022 # except Exception as error:
5023 # logger.error("%s: %s: accept on socket failed: %s", self, host, error)
5024 # if p.poll() is not None:
5025 # logger.error("%s: %s: helper app quit: %s", self, host, comm_error(p))
5026 # raise
5027
5028 # def stopping_proc(self, host, p, conn):
5029 # logger.debug("%s: %s: closing socket %s", self, host, conn)
5030 # conn[0].close()