]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/lib/ospf.py
tests: fix create_router_ospf6 to use ospf6 instead of ospf
[mirror_frr.git] / tests / topotests / lib / ospf.py
CommitLineData
4256a209 1#
2# Copyright (c) 2020 by VMware, Inc. ("VMware")
3# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
4# ("NetDEF") in this file.
5#
6# Permission to use, copy, modify, and/or distribute this software
7# for any purpose with or without fee is hereby granted, provided
8# that the above copyright notice and this permission notice appear
9# in all copies.
10#
11# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
12# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
14# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
15# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
16# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
17# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
18# OF THIS SOFTWARE.
19#
20
21from copy import deepcopy
22import traceback
23from time import sleep
24from lib.topolog import logger
25import ipaddr
61196140 26from lib.topotest import frr_unicode
4256a209 27
28# Import common_config to use commomnly used APIs
701a0192 29from lib.common_config import (
30 create_common_configuration,
31 InvalidCLIError,
32 retry,
33 generate_ips,
34 check_address_types,
35 validate_ip_address,
36 run_frr_cmd,
37)
4256a209 38
39LOGDIR = "/tmp/topotests/"
40TMPDIR = None
41
42################################
43# Configure procs
44################################
45
701a0192 46
47def create_router_ospf(tgen, topo, input_dict=None, build=False, load_config=True):
4256a209 48 """
49 API to configure ospf on router.
50
51 Parameters
52 ----------
53 * `tgen` : Topogen object
54 * `topo` : json file data
55 * `input_dict` : Input dict data, required when configuring from testcase
56 * `build` : Only for initial setup phase this is set as True.
57 * `load_config` : Loading the config to router this is set as True.
58
59 Usage
60 -----
61 input_dict = {
62 "r1": {
63 "ospf": {
64 "router_id": "22.22.22.22",
9458be1a 65 "area": [{ "id": "0.0.0.0", "type": "nssa"}]
4256a209 66 }
67 }
68
69 result = create_router_ospf(tgen, topo, input_dict)
70
71 Returns
72 -------
73 True or False
74 """
75 logger.debug("Entering lib API: create_router_ospf()")
76 result = False
77
78 if not input_dict:
79 input_dict = deepcopy(topo)
80 else:
81 topo = topo["routers"]
82 input_dict = deepcopy(input_dict)
83
84 for router in input_dict.keys():
85 if "ospf" not in input_dict[router]:
86 logger.debug("Router %s: 'ospf' not present in input_dict", router)
87 continue
88
701a0192 89 result = __create_ospf_global(tgen, input_dict, router, build, load_config)
4256a209 90 if result is True:
91 ospf_data = input_dict[router]["ospf"]
92
4256a209 93 logger.debug("Exiting lib API: create_router_ospf()")
94 return result
95
96
889da676 97def __create_ospf_global(tgen, input_dict, router, build=False, load_config=True, ospf='ospf'):
4256a209 98 """
99 Helper API to create ospf global configuration.
100
101 Parameters
102 ----------
103 * `tgen` : Topogen object
104 * `input_dict` : Input dict data, required when configuring from testcase
105 * `router` : router to be configured.
106 * `build` : Only for initial setup phase this is set as True.
107 * `load_config` : Loading the config to router this is set as True.
889da676 108 * `ospf` : either 'ospf' or 'ospf6'
4256a209 109
110 Returns
111 -------
112 True or False
113 """
114
115 result = False
116 logger.debug("Entering lib API: __create_ospf_global()")
117 try:
118
889da676 119 ospf_data = input_dict[router][ospf]
4256a209 120 del_ospf_action = ospf_data.setdefault("delete", False)
121 if del_ospf_action:
889da676 122 config_data = ["no router {}".format(ospf)]
701a0192 123 result = create_common_configuration(
889da676 124 tgen, router, config_data, ospf, build, load_config
701a0192 125 )
4256a209 126 return result
127
128 config_data = []
889da676 129 cmd = "router {}".format(ospf)
4256a209 130
131 config_data.append(cmd)
132
133 # router id
134 router_id = ospf_data.setdefault("router_id", None)
135 del_router_id = ospf_data.setdefault("del_router_id", False)
136 if del_router_id:
889da676 137 config_data.append("no {} router-id".format(ospf))
4256a209 138 if router_id:
889da676 139 config_data.append("{} router-id {}".format(ospf, router_id))
4256a209 140
141 # redistribute command
142 redistribute_data = ospf_data.setdefault("redistribute", {})
143 if redistribute_data:
144 for redistribute in redistribute_data:
145 if "redist_type" not in redistribute:
701a0192 146 logger.debug(
147 "Router %s: 'redist_type' not present in " "input_dict", router
148 )
4256a209 149 else:
701a0192 150 cmd = "redistribute {}".format(redistribute["redist_type"])
4256a209 151 for red_type in redistribute_data:
152 if "route_map" in red_type:
701a0192 153 cmd = cmd + " route-map {}".format(red_type["route_map"])
4256a209 154 del_action = redistribute.setdefault("delete", False)
155 if del_action:
156 cmd = "no {}".format(cmd)
157 config_data.append(cmd)
889da676 158
701a0192 159 # area information
4256a209 160 area_data = ospf_data.setdefault("area", {})
161 if area_data:
162 for area in area_data:
163 if "id" not in area:
701a0192 164 logger.debug(
165 "Router %s: 'area id' not present in " "input_dict", router
166 )
4256a209 167 else:
168 cmd = "area {}".format(area["id"])
169
170 if "type" in area:
171 cmd = cmd + " {}".format(area["type"])
172
173 del_action = area.setdefault("delete", False)
174 if del_action:
175 cmd = "no {}".format(cmd)
176 config_data.append(cmd)
4256a209 177
178 # summary information
179 summary_data = ospf_data.setdefault("summary-address", {})
180 if summary_data:
181 for summary in summary_data:
182 if "prefix" not in summary:
701a0192 183 logger.debug(
184 "Router %s: 'summary-address' not present in " "input_dict",
185 router,
186 )
4256a209 187 else:
701a0192 188 cmd = "summary {}/{}".format(summary["prefix"], summary["mask"])
4256a209 189
190 _tag = summary.setdefault("tag", None)
191 if _tag:
192 cmd = "{} tag {}".format(cmd, _tag)
193
194 _advertise = summary.setdefault("advertise", True)
195 if not _advertise:
196 cmd = "{} no-advertise".format(cmd)
197
198 del_action = summary.setdefault("delete", False)
199 if del_action:
200 cmd = "no {}".format(cmd)
201 config_data.append(cmd)
889da676 202
701a0192 203 result = create_common_configuration(
889da676 204 tgen, router, config_data, ospf, build, load_config
701a0192 205 )
4256a209 206
207 except InvalidCLIError:
208 # Traceback
209 errormsg = traceback.format_exc()
210 logger.error(errormsg)
211 return errormsg
212
213 logger.debug("Exiting lib API: create_ospf_global()")
214 return result
215
216
701a0192 217def create_router_ospf6(tgen, topo, input_dict=None, build=False, load_config=True):
4256a209 218 """
219 API to configure ospf on router
220
221 Parameters
222 ----------
223 * `tgen` : Topogen object
224 * `topo` : json file data
225 * `input_dict` : Input dict data, required when configuring from testcase
226 * `build` : Only for initial setup phase this is set as True.
227
228 Usage
229 -----
230 input_dict = {
231 "r1": {
232 "ospf6": {
233 "router_id": "22.22.22.22",
234 }
235 }
236
237 Returns
238 -------
239 True or False
240 """
12011c40 241 logger.debug("Entering lib API: create_router_ospf6()")
4256a209 242 result = False
243
244 if not input_dict:
245 input_dict = deepcopy(topo)
246 else:
247 topo = topo["routers"]
248 input_dict = deepcopy(input_dict)
249 for router in input_dict.keys():
12011c40 250 if "ospf6" not in input_dict[router]:
251 logger.debug("Router %s: 'ospf6' not present in input_dict", router)
4256a209 252 continue
253
12011c40 254 result = __create_ospf_global(
255 tgen, input_dict, router, build, load_config, "ospf6"
256 )
4256a209 257
12011c40 258 logger.debug("Exiting lib API: create_router_ospf6()")
4256a209 259 return result
260
261
701a0192 262def config_ospf_interface(tgen, topo, input_dict=None, build=False, load_config=True):
4256a209 263 """
264 API to configure ospf on router.
265
266 Parameters
267 ----------
268 * `tgen` : Topogen object
269 * `topo` : json file data
270 * `input_dict` : Input dict data, required when configuring from testcase
271 * `build` : Only for initial setup phase this is set as True.
272 * `load_config` : Loading the config to router this is set as True.
273
274 Usage
275 -----
276 r1_ospf_auth = {
277 "r1": {
278 "links": {
279 "r2": {
280 "ospf": {
9458be1a 281 "authentication": "message-digest",
4256a209 282 "authentication-key": "ospf",
283 "message-digest-key": "10"
284 }
285 }
286 }
287 }
288 }
289 result = config_ospf_interface(tgen, topo, r1_ospf_auth)
290
291 Returns
292 -------
293 True or False
294 """
295 logger.debug("Enter lib config_ospf_interface")
296 if not input_dict:
297 input_dict = deepcopy(topo)
298 else:
299 input_dict = deepcopy(input_dict)
300 for router in input_dict.keys():
301 config_data = []
701a0192 302 for lnk in input_dict[router]["links"].keys():
303 if "ospf" not in input_dict[router]["links"][lnk]:
304 logger.debug(
305 "Router %s: ospf configs is not present in"
306 "input_dict, passed input_dict",
307 router,
308 input_dict,
309 )
4256a209 310 continue
701a0192 311 ospf_data = input_dict[router]["links"][lnk]["ospf"]
4256a209 312 data_ospf_area = ospf_data.setdefault("area", None)
313 data_ospf_auth = ospf_data.setdefault("authentication", None)
314 data_ospf_dr_priority = ospf_data.setdefault("priority", None)
315 data_ospf_cost = ospf_data.setdefault("cost", None)
316
317 try:
701a0192 318 intf = topo["routers"][router]["links"][lnk]["interface"]
4256a209 319 except KeyError:
701a0192 320 intf = topo["switches"][router]["links"][lnk]["interface"]
4256a209 321
322 # interface
323 cmd = "interface {}".format(intf)
324
325 config_data.append(cmd)
326 # interface area config
327 if data_ospf_area:
328 cmd = "ip ospf area {}".format(data_ospf_area)
329 config_data.append(cmd)
9458be1a 330
4256a209 331 # interface ospf auth
332 if data_ospf_auth:
701a0192 333 if data_ospf_auth == "null":
4256a209 334 cmd = "ip ospf authentication null"
701a0192 335 elif data_ospf_auth == "message-digest":
4256a209 336 cmd = "ip ospf authentication message-digest"
337 else:
338 cmd = "ip ospf authentication"
339
701a0192 340 if "del_action" in ospf_data:
4256a209 341 cmd = "no {}".format(cmd)
342 config_data.append(cmd)
343
344 if "message-digest-key" in ospf_data:
345 cmd = "ip ospf message-digest-key {} md5 {}".format(
701a0192 346 ospf_data["message-digest-key"], ospf_data["authentication-key"]
347 )
348 if "del_action" in ospf_data:
4256a209 349 cmd = "no {}".format(cmd)
350 config_data.append(cmd)
351
701a0192 352 if (
353 "authentication-key" in ospf_data
354 and "message-digest-key" not in ospf_data
355 ):
356 cmd = "ip ospf authentication-key {}".format(
357 ospf_data["authentication-key"]
358 )
359 if "del_action" in ospf_data:
4256a209 360 cmd = "no {}".format(cmd)
361 config_data.append(cmd)
362
363 # interface ospf dr priority
364 if data_ospf_dr_priority in ospf_data:
701a0192 365 cmd = "ip ospf priority {}".format(ospf_data["priority"])
366 if "del_action" in ospf_data:
4256a209 367 cmd = "no {}".format(cmd)
368 config_data.append(cmd)
369
370 # interface ospf cost
371 if data_ospf_cost in ospf_data:
701a0192 372 cmd = "ip ospf cost {}".format(ospf_data["cost"])
373 if "del_action" in ospf_data:
4256a209 374 cmd = "no {}".format(cmd)
375 config_data.append(cmd)
376
377 if build:
378 return config_data
379 else:
701a0192 380 result = create_common_configuration(
381 tgen, router, config_data, "interface_config", build=build
382 )
4256a209 383 logger.debug("Exiting lib API: create_igmp_config()")
384 return result
385
701a0192 386
4256a209 387def clear_ospf(tgen, router):
388 """
389 This API is to clear ospf neighborship by running
390 clear ip ospf interface * command,
391
392 Parameters
393 ----------
394 * `tgen`: topogen object
395 * `router`: device under test
396
397 Usage
398 -----
399 clear_ospf(tgen, "r1")
400 """
401
402 logger.debug("Entering lib API: clear_ospf()")
403 if router not in tgen.routers():
404 return False
405
406 rnode = tgen.routers()[router]
407
408 # Clearing OSPF
409 logger.info("Clearing ospf process for router %s..", router)
410
411 run_frr_cmd(rnode, "clear ip ospf interface ")
412
413 logger.debug("Exiting lib API: clear_ospf()")
414
415
88b7d3e7 416def redistribute_ospf(tgen, topo, dut, route_type, **kwargs):
417 """
418 Redstribution of routes inside ospf.
419
420 Parameters
421 ----------
422 * `tgen`: Topogen object
423 * `topo` : json file data
424 * `dut`: device under test
425 * `route_type`: "static" or "connected" or ....
426 * `kwargs`: pass extra information (see below)
427
428 Usage
429 -----
430 redistribute_ospf(tgen, topo, "r0", "static", delete=True)
431 redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
432 """
433
434 ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": route_type}]}}}
435 for k, v in kwargs.items():
436 ospf_red[dut]["ospf"]["redistribute"][0][k] = v
437
438 result = create_router_ospf(tgen, topo, ospf_red)
439 assert result is True, "Testcase : Failed \n Error: {}".format(result)
440
441
4256a209 442################################
443# Verification procs
444################################
445@retry(attempts=40, wait=2, return_is_str=True)
446def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
447 """
448 This API is to verify ospf neighborship by running
449 show ip ospf neighbour command,
450
451 Parameters
452 ----------
453 * `tgen` : Topogen object
454 * `topo` : json file data
455 * `dut`: device under test
456 * `input_dict` : Input dict data, required when configuring from testcase
457 * `lan` : verify neighbors in lan topology
458
459 Usage
460 -----
461 1. To check FULL neighbors.
462 verify_ospf_neighbor(tgen, topo, dut=dut)
463
464 2. To check neighbors with their roles.
465 input_dict = {
466 "r0": {
467 "ospf": {
468 "neighbors": {
469 "r1": {
470 "state": "Full",
471 "role": "DR"
472 },
473 "r2": {
474 "state": "Full",
475 "role": "DROther"
476 },
477 "r3": {
478 "state": "Full",
479 "role": "DROther"
480 }
481 }
482 }
483 }
484 }
485 result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
486
487 Returns
488 -------
489 True or False (Error Message)
490 """
491 logger.debug("Entering lib API: verify_ospf_neighbor()")
492 result = False
493 if input_dict:
11761ab0 494 for router, rnode in tgen.routers().items():
701a0192 495 if "ospf" not in topo["routers"][router]:
4256a209 496 continue
497
498 if dut is not None and dut != router:
499 continue
500
501 logger.info("Verifying OSPF neighborship on router %s:", router)
701a0192 502 show_ospf_json = run_frr_cmd(
9458be1a 503 rnode, "show ip ospf neighbor all json", isjson=True
701a0192 504 )
4256a209 505
506 # Verifying output dictionary show_ospf_json is empty or not
507 if not bool(show_ospf_json):
508 errormsg = "OSPF is not running"
509 return errormsg
510
511 ospf_data_list = input_dict[router]["ospf"]
701a0192 512 ospf_nbr_list = ospf_data_list["neighbors"]
4256a209 513
514 for ospf_nbr, nbr_data in ospf_nbr_list.items():
701a0192 515 data_ip = topo["routers"][ospf_nbr]["links"]
516 data_rid = topo["routers"][ospf_nbr]["ospf"]["router_id"]
4256a209 517 if ospf_nbr in data_ip:
518 nbr_details = nbr_data[ospf_nbr]
519 elif lan:
701a0192 520 for switch in topo["switches"]:
521 if "ospf" in topo["switches"][switch]["links"][router]:
522 neighbor_ip = data_ip[switch]["ipv4"].split("/")[0]
4256a209 523 else:
524 continue
525 else:
701a0192 526 neighbor_ip = data_ip[router]["ipv4"].split("/")[0]
4256a209 527
528 nh_state = None
529 neighbor_ip = neighbor_ip.lower()
530 nbr_rid = data_rid
531 try:
701a0192 532 nh_state = show_ospf_json[nbr_rid][0]["state"].split("/")[0]
533 intf_state = show_ospf_json[nbr_rid][0]["state"].split("/")[1]
4256a209 534 except KeyError:
701a0192 535 errormsg = "[DUT: {}] OSPF peer {} missing".format(router, nbr_rid)
4256a209 536 return errormsg
537
701a0192 538 nbr_state = nbr_data.setdefault("state", None)
539 nbr_role = nbr_data.setdefault("role", None)
4256a209 540
541 if nbr_state:
542 if nbr_state == nh_state:
701a0192 543 logger.info(
544 "[DUT: {}] OSPF Nbr is {}:{} State {}".format(
545 router, ospf_nbr, nbr_rid, nh_state
546 )
547 )
4256a209 548 result = True
549 else:
701a0192 550 errormsg = (
551 "[DUT: {}] OSPF is not Converged, neighbor"
552 " state is {}".format(router, nh_state)
553 )
4256a209 554 return errormsg
555 if nbr_role:
556 if nbr_role == intf_state:
701a0192 557 logger.info(
558 "[DUT: {}] OSPF Nbr is {}: {} Role {}".format(
559 router, ospf_nbr, nbr_rid, nbr_role
560 )
561 )
4256a209 562 else:
701a0192 563 errormsg = (
564 "[DUT: {}] OSPF is not Converged with rid"
565 "{}, role is {}".format(router, nbr_rid, intf_state)
566 )
4256a209 567 return errormsg
568 continue
569 else:
11761ab0 570 for router, rnode in tgen.routers().items():
701a0192 571 if "ospf" not in topo["routers"][router]:
4256a209 572 continue
573
574 if dut is not None and dut != router:
575 continue
576
577 logger.info("Verifying OSPF neighborship on router %s:", router)
701a0192 578 show_ospf_json = run_frr_cmd(
579 rnode, "show ip ospf neighbor all json", isjson=True
580 )
4256a209 581 # Verifying output dictionary show_ospf_json is empty or not
582 if not bool(show_ospf_json):
583 errormsg = "OSPF is not running"
584 return errormsg
585
586 ospf_data_list = topo["routers"][router]["ospf"]
701a0192 587 ospf_neighbors = ospf_data_list["neighbors"]
4256a209 588 total_peer = 0
589 total_peer = len(ospf_neighbors.keys())
590 no_of_ospf_nbr = 0
701a0192 591 ospf_nbr_list = ospf_data_list["neighbors"]
4256a209 592 no_of_peer = 0
593 for ospf_nbr, nbr_data in ospf_nbr_list.items():
594 if nbr_data:
701a0192 595 data_ip = topo["routers"][nbr_data["nbr"]]["links"]
596 data_rid = topo["routers"][nbr_data["nbr"]]["ospf"]["router_id"]
4256a209 597 else:
701a0192 598 data_ip = topo["routers"][ospf_nbr]["links"]
599 data_rid = topo["routers"][ospf_nbr]["ospf"]["router_id"]
4256a209 600 if ospf_nbr in data_ip:
601 nbr_details = nbr_data[ospf_nbr]
602 elif lan:
701a0192 603 for switch in topo["switches"]:
604 if "ospf" in topo["switches"][switch]["links"][router]:
605 neighbor_ip = data_ip[switch]["ipv4"].split("/")[0]
4256a209 606 else:
607 continue
608 else:
701a0192 609 neighbor_ip = data_ip[router]["ipv4"].split("/")[0]
4256a209 610
611 nh_state = None
612 neighbor_ip = neighbor_ip.lower()
613 nbr_rid = data_rid
614 try:
701a0192 615 nh_state = show_ospf_json[nbr_rid][0]["state"].split("/")[0]
4256a209 616 except KeyError:
701a0192 617 errormsg = "[DUT: {}] OSPF peer {} missing,from " "{} ".format(
618 router, nbr_rid, ospf_nbr
619 )
4256a209 620 return errormsg
621
701a0192 622 if nh_state == "Full":
4256a209 623 no_of_peer += 1
624
625 if no_of_peer == total_peer:
626 logger.info("[DUT: {}] OSPF is Converged".format(router))
627 result = True
628 else:
701a0192 629 errormsg = "[DUT: {}] OSPF is not Converged".format(router)
4256a209 630 return errormsg
631
632 logger.debug("Exiting API: verify_ospf_neighbor()")
633 return result
634
701a0192 635
b29a56b3 636@retry(attempts=21, wait=2, return_is_str=True)
701a0192 637def verify_ospf_rib(
638 tgen, dut, input_dict, next_hop=None, tag=None, metric=None, fib=None
639):
4256a209 640 """
641 This API is to verify ospf routes by running
642 show ip ospf route command.
643
644 Parameters
645 ----------
646 * `tgen` : Topogen object
647 * `dut`: device under test
648 * `input_dict` : Input dict data, required when configuring from testcase
649 * `next_hop` : next to be verified
650 * `tag` : tag to be verified
651 * `metric` : metric to be verified
652 * `fib` : True if the route is installed in FIB.
653
654 Usage
655 -----
656 input_dict = {
657 "r1": {
658 "static_routes": [
659 {
660 "network": ip_net,
661 "no_of_ip": 1,
662 "routeType": "N"
663 }
664 ]
665 }
666 }
667
668 result = verify_ospf_rib(tgen, dut, input_dict,next_hop=nh)
669
670 Returns
671 -------
672 True or False (Error Message)
673 """
674
675 logger.info("Entering lib API: verify_ospf_rib()")
676 result = False
677 router_list = tgen.routers()
678 additional_nexthops_in_required_nhs = []
679 found_hops = []
680 for routerInput in input_dict.keys():
11761ab0 681 for router, rnode in router_list.items():
4256a209 682 if router != dut:
683 continue
684
685 logger.info("Checking router %s RIB:", router)
686
687 # Verifying RIB routes
688 command = "show ip ospf route"
689
690 found_routes = []
691 missing_routes = []
692
701a0192 693 if (
694 "static_routes" in input_dict[routerInput]
695 or "prefix" in input_dict[routerInput]
696 ):
4256a209 697 if "prefix" in input_dict[routerInput]:
698 static_routes = input_dict[routerInput]["prefix"]
699 else:
700 static_routes = input_dict[routerInput]["static_routes"]
701
4256a209 702 for static_route in static_routes:
703 cmd = "{}".format(command)
704
705 cmd = "{} json".format(cmd)
706
701a0192 707 ospf_rib_json = run_frr_cmd(rnode, cmd, isjson=True)
4256a209 708
709 # Verifying output dictionary ospf_rib_json is not empty
710 if bool(ospf_rib_json) is False:
701a0192 711 errormsg = (
712 "[DUT: {}] No routes found in OSPF route "
4256a209 713 "table".format(router)
701a0192 714 )
4256a209 715 return errormsg
716
717 network = static_route["network"]
718 no_of_ip = static_route.setdefault("no_of_ip", 1)
719 _tag = static_route.setdefault("tag", None)
720 _rtype = static_route.setdefault("routeType", None)
721
4256a209 722 # Generating IPs for verification
723 ip_list = generate_ips(network, no_of_ip)
724 st_found = False
725 nh_found = False
726
727 for st_rt in ip_list:
61196140 728 st_rt = str(ipaddr.IPNetwork(frr_unicode(st_rt)))
4256a209 729
730 _addr_type = validate_ip_address(st_rt)
701a0192 731 if _addr_type != "ipv4":
4256a209 732 continue
733
734 if st_rt in ospf_rib_json:
735 st_found = True
736 found_routes.append(st_rt)
737
738 if fib and next_hop:
739 if type(next_hop) is not list:
740 next_hop = [next_hop]
741
742 for mnh in range(0, len(ospf_rib_json[st_rt])):
701a0192 743 if (
744 "fib"
745 in ospf_rib_json[st_rt][mnh]["nexthops"][0]
746 ):
747 found_hops.append(
748 [
749 rib_r["ip"]
750 for rib_r in ospf_rib_json[st_rt][mnh][
751 "nexthops"
752 ]
753 ]
754 )
4256a209 755
756 if found_hops[0]:
701a0192 757 missing_list_of_nexthops = set(
758 found_hops[0]
759 ).difference(next_hop)
760 additional_nexthops_in_required_nhs = set(
761 next_hop
762 ).difference(found_hops[0])
4256a209 763
764 if additional_nexthops_in_required_nhs:
765 logger.info(
766 "Nexthop "
767 "%s is not active for route %s in "
768 "RIB of router %s\n",
769 additional_nexthops_in_required_nhs,
701a0192 770 st_rt,
771 dut,
772 )
4256a209 773 errormsg = (
774 "Nexthop {} is not active"
775 " for route {} in RIB of router"
776 " {}\n".format(
701a0192 777 additional_nexthops_in_required_nhs,
778 st_rt,
779 dut,
780 )
781 )
4256a209 782 return errormsg
783 else:
784 nh_found = True
785
786 elif next_hop and fib is None:
787 if type(next_hop) is not list:
788 next_hop = [next_hop]
701a0192 789 found_hops = [
790 rib_r["ip"]
791 for rib_r in ospf_rib_json[st_rt]["nexthops"]
792 ]
4256a209 793
794 if found_hops:
701a0192 795 missing_list_of_nexthops = set(
796 found_hops
797 ).difference(next_hop)
798 additional_nexthops_in_required_nhs = set(
799 next_hop
800 ).difference(found_hops)
4256a209 801
802 if additional_nexthops_in_required_nhs:
803 logger.info(
701a0192 804 "Missing nexthop %s for route"
805 " %s in RIB of router %s\n",
4256a209 806 additional_nexthops_in_required_nhs,
701a0192 807 st_rt,
808 dut,
809 )
810 errormsg = (
811 "Nexthop {} is Missing for "
812 "route {} in RIB of router {}\n".format(
813 additional_nexthops_in_required_nhs,
814 st_rt,
815 dut,
816 )
817 )
4256a209 818 return errormsg
819 else:
820 nh_found = True
821 if _rtype:
701a0192 822 if "routeType" not in ospf_rib_json[st_rt]:
823 errormsg = (
824 "[DUT: {}]: routeType missing"
9458be1a 825 " for route {} in OSPF RIB \n".format(
826 dut, st_rt
827 )
701a0192 828 )
4256a209 829 return errormsg
701a0192 830 elif _rtype != ospf_rib_json[st_rt]["routeType"]:
831 errormsg = (
832 "[DUT: {}]: routeType mismatch"
9458be1a 833 " for route {} in OSPF RIB \n".format(
834 dut, st_rt
835 )
701a0192 836 )
4256a209 837 return errormsg
838 else:
701a0192 839 logger.info(
9458be1a 840 "[DUT: {}]: Found routeType {}"
841 " for route {}".format(dut, _rtype, st_rt)
701a0192 842 )
4256a209 843 if tag:
701a0192 844 if "tag" not in ospf_rib_json[st_rt]:
845 errormsg = (
846 "[DUT: {}]: tag is not"
847 " present for"
848 " route {} in RIB \n".format(dut, st_rt)
849 )
4256a209 850 return errormsg
851
701a0192 852 if _tag != ospf_rib_json[st_rt]["tag"]:
853 errormsg = (
854 "[DUT: {}]: tag value {}"
855 " is not matched for"
9fa6ec14 856 " route {} in RIB \n".format(
857 dut,
858 _tag,
859 st_rt,
860 )
701a0192 861 )
4256a209 862 return errormsg
863
864 if metric is not None:
701a0192 865 if "type2cost" not in ospf_rib_json[st_rt]:
866 errormsg = (
867 "[DUT: {}]: metric is"
868 " not present for"
869 " route {} in RIB \n".format(dut, st_rt)
870 )
4256a209 871 return errormsg
872
701a0192 873 if metric != ospf_rib_json[st_rt]["type2cost"]:
874 errormsg = (
875 "[DUT: {}]: metric value "
876 "{} is not matched for "
9fa6ec14 877 "route {} in RIB \n".format(
878 dut,
879 metric,
880 st_rt,
881 )
701a0192 882 )
4256a209 883 return errormsg
884
885 else:
886 missing_routes.append(st_rt)
887
888 if nh_found:
701a0192 889 logger.info(
890 "[DUT: {}]: Found next_hop {} for all OSPF"
891 " routes in RIB".format(router, next_hop)
892 )
4256a209 893
894 if len(missing_routes) > 0:
701a0192 895 errormsg = "[DUT: {}]: Missing route in RIB, " "routes: {}".format(
896 dut, missing_routes
897 )
4256a209 898 return errormsg
899
900 if found_routes:
701a0192 901 logger.info(
902 "[DUT: %s]: Verified routes in RIB, found" " routes are: %s\n",
903 dut,
904 found_routes,
905 )
4256a209 906 result = True
907
908 logger.info("Exiting lib API: verify_ospf_rib()")
909 return result
910
911
912@retry(attempts=10, wait=2, return_is_str=True)
701a0192 913def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None):
4256a209 914 """
915 This API is to verify ospf routes by running
916 show ip ospf interface command.
917
918 Parameters
919 ----------
920 * `tgen` : Topogen object
921 * `topo` : topology descriptions
922 * `dut`: device under test
923 * `lan`: if set to true this interface belongs to LAN.
924 * `input_dict` : Input dict data, required when configuring from testcase
925
926 Usage
927 -----
928 input_dict= {
929 'r0': {
930 'links':{
931 's1': {
932 'ospf':{
933 'priority':98,
934 'timerDeadSecs': 4,
935 'area': '0.0.0.3',
936 'mcastMemberOspfDesignatedRouters': True,
937 'mcastMemberOspfAllRouters': True,
938 'ospfEnabled': True,
939
940 }
941 }
942 }
943 }
944 }
945 result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
946
947 Returns
948 -------
949 True or False (Error Message)
950 """
951
952 logger.debug("Entering lib API: verify_ospf_interface()")
953 result = False
11761ab0 954 for router, rnode in tgen.routers().items():
701a0192 955 if "ospf" not in topo["routers"][router]:
4256a209 956 continue
957
958 if dut is not None and dut != router:
959 continue
960
961 logger.info("Verifying OSPF interface on router %s:", router)
701a0192 962 show_ospf_json = run_frr_cmd(rnode, "show ip ospf interface json", isjson=True)
4256a209 963
964 # Verifying output dictionary show_ospf_json is empty or not
965 if not bool(show_ospf_json):
966 errormsg = "OSPF is not running"
967 return errormsg
968
969 # To find neighbor ip type
970 ospf_intf_data = input_dict[router]["links"]
971 for ospf_intf, intf_data in ospf_intf_data.items():
701a0192 972 intf = topo["routers"][router]["links"][ospf_intf]["interface"]
973 if intf in show_ospf_json["interfaces"]:
974 for intf_attribute in intf_data["ospf"]:
975 if (
976 intf_data["ospf"][intf_attribute]
977 == show_ospf_json["interfaces"][intf][intf_attribute]
978 ):
979 logger.info(
980 "[DUT: %s] OSPF interface %s: %s is %s",
981 router,
982 intf,
983 intf_attribute,
984 intf_data["ospf"][intf_attribute],
985 )
4256a209 986 else:
701a0192 987 errormsg = "[DUT: {}] OSPF interface {}: {} is {}, \
988 Expected is {}".format(
989 router,
990 intf,
991 intf_attribute,
992 intf_data["ospf"][intf_attribute],
993 show_ospf_json["interfaces"][intf][intf_attribute],
994 )
4256a209 995 return errormsg
996 result = True
997 logger.debug("Exiting API: verify_ospf_interface()")
998 return result
999
1000
b29a56b3 1001@retry(attempts=11, wait=2, return_is_str=True)
4256a209 1002def verify_ospf_database(tgen, topo, dut, input_dict):
1003 """
1004 This API is to verify ospf lsa's by running
1005 show ip ospf database command.
1006
1007 Parameters
1008 ----------
1009 * `tgen` : Topogen object
1010 * `dut`: device under test
1011 * `input_dict` : Input dict data, required when configuring from testcase
1012 * `topo` : next to be verified
1013
1014 Usage
1015 -----
1016 input_dict = {
1017 "areas": {
1018 "0.0.0.0": {
1019 "Router Link States": {
1020 "100.1.1.0-100.1.1.0": {
1021 "LSID": "100.1.1.0",
1022 "Advertised router": "100.1.1.0",
1023 "LSA Age": 130,
1024 "Sequence Number": "80000006",
1025 "Checksum": "a703",
1026 "Router links": 3
1027 }
1028 },
1029 "Net Link States": {
1030 "10.0.0.2-100.1.1.1": {
1031 "LSID": "10.0.0.2",
1032 "Advertised router": "100.1.1.1",
1033 "LSA Age": 137,
1034 "Sequence Number": "80000001",
1035 "Checksum": "9583"
1036 }
1037 },
1038 },
1039 }
1040 }
1041 result = verify_ospf_database(tgen, topo, dut, input_dict)
1042
1043 Returns
1044 -------
1045 True or False (Error Message)
1046 """
1047
1048 result = False
1049 router = dut
1050 logger.debug("Entering lib API: verify_ospf_database()")
1051
701a0192 1052 if "ospf" not in topo["routers"][dut]:
1053 errormsg = "[DUT: {}] OSPF is not configured on the router.".format(dut)
4256a209 1054 return errormsg
1055
1056 rnode = tgen.routers()[dut]
1057
1058 logger.info("Verifying OSPF interface on router %s:", dut)
701a0192 1059 show_ospf_json = run_frr_cmd(rnode, "show ip ospf database json", isjson=True)
4256a209 1060 # Verifying output dictionary show_ospf_json is empty or not
1061 if not bool(show_ospf_json):
1062 errormsg = "OSPF is not running"
1063 return errormsg
1064
1065 # for inter and inter lsa's
1066 ospf_db_data = input_dict.setdefault("areas", None)
701a0192 1067 ospf_external_lsa = input_dict.setdefault("AS External Link States", None)
4256a209 1068 if ospf_db_data:
701a0192 1069 for ospf_area, area_lsa in ospf_db_data.items():
1070 if ospf_area in show_ospf_json["areas"]:
1071 if "Router Link States" in area_lsa:
1072 for lsa in area_lsa["Router Link States"]:
1073 if (
1074 lsa
1075 in show_ospf_json["areas"][ospf_area]["Router Link States"]
1076 ):
1077 logger.info(
1078 "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
1079 router,
1080 ospf_area,
1081 lsa,
1082 )
1083 result = True
1084 else:
1085 errormsg = (
1086 "[DUT: {}] OSPF LSDB area {}: expected"
4256a209 1087 " Router LSA is {}".format(router, ospf_area, lsa)
701a0192 1088 )
1089 return errormsg
1090 if "Net Link States" in area_lsa:
1091 for lsa in area_lsa["Net Link States"]:
1092 if lsa in show_ospf_json["areas"][ospf_area]["Net Link States"]:
1093 logger.info(
1094 "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
1095 router,
1096 ospf_area,
1097 lsa,
1098 )
1099 result = True
1100 else:
1101 errormsg = (
1102 "[DUT: {}] OSPF LSDB area {}: expected"
4256a209 1103 " Network LSA is {}".format(router, ospf_area, lsa)
701a0192 1104 )
1105 return errormsg
1106 if "Summary Link States" in area_lsa:
1107 for lsa in area_lsa["Summary Link States"]:
1108 if (
1109 lsa
1110 in show_ospf_json["areas"][ospf_area]["Summary Link States"]
1111 ):
1112 logger.info(
1113 "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
1114 router,
1115 ospf_area,
1116 lsa,
1117 )
1118 result = True
1119 else:
1120 errormsg = (
1121 "[DUT: {}] OSPF LSDB area {}: expected"
4256a209 1122 " Summary LSA is {}".format(router, ospf_area, lsa)
701a0192 1123 )
1124 return errormsg
1125 if "ASBR-Summary Link States" in area_lsa:
1126 for lsa in area_lsa["ASBR-Summary Link States"]:
1127 if (
1128 lsa
1129 in show_ospf_json["areas"][ospf_area][
1130 "ASBR-Summary Link States"
1131 ]
1132 ):
1133 logger.info(
1134 "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
1135 router,
1136 ospf_area,
1137 lsa,
1138 )
1139 result = True
1140 else:
1141 errormsg = (
1142 "[DUT: {}] OSPF LSDB area {}: expected"
1143 " ASBR Summary LSA is {}".format(router, ospf_area, lsa)
1144 )
1145 return errormsg
4256a209 1146 if ospf_external_lsa:
701a0192 1147 for ospf_ext_lsa, ext_lsa_data in ospf_external_lsa.items():
1148 if ospf_ext_lsa in show_ospf_json["AS External Link States"]:
1149 logger.info(
1150 "[DUT: %s] OSPF LSDB:External LSA %s", router, ospf_ext_lsa
1151 )
1152 result = True
1153 else:
1154 errormsg = (
1155 "[DUT: {}] OSPF LSDB : expected"
1156 " External LSA is {}".format(router, ospf_ext_lsa)
1157 )
1158 return errormsg
4256a209 1159
1160 logger.debug("Exiting API: verify_ospf_database()")
1161 return result
1162
1163
4256a209 1164@retry(attempts=10, wait=2, return_is_str=True)
1165def verify_ospf_summary(tgen, topo, dut, input_dict):
1166 """
1167 This API is to verify ospf routes by running
1168 show ip ospf interface command.
1169
1170 Parameters
1171 ----------
1172 * `tgen` : Topogen object
1173 * `topo` : topology descriptions
1174 * `dut`: device under test
1175 * `input_dict` : Input dict data, required when configuring from testcase
1176
1177 Usage
1178 -----
1179 input_dict = {
1180 "11.0.0.0/8": {
1181 "Summary address": "11.0.0.0/8",
1182 "Metric-type": "E2",
1183 "Metric": 20,
1184 "Tag": 0,
1185 "External route count": 5
1186 }
1187 }
1188 result = verify_ospf_summary(tgen, topo, dut, input_dict)
1189
1190 Returns
1191 -------
1192 True or False (Error Message)
1193 """
1194
1195 logger.debug("Entering lib API: verify_ospf_summary()")
1196 result = False
1197 router = dut
1198
1199 logger.info("Verifying OSPF summary on router %s:", router)
1200
701a0192 1201 if "ospf" not in topo["routers"][dut]:
1202 errormsg = "[DUT: {}] OSPF is not configured on the router.".format(router)
4256a209 1203 return errormsg
1204
1205 rnode = tgen.routers()[dut]
701a0192 1206 show_ospf_json = run_frr_cmd(rnode, "show ip ospf summary detail json", isjson=True)
4256a209 1207
1208 # Verifying output dictionary show_ospf_json is empty or not
1209 if not bool(show_ospf_json):
1210 errormsg = "OSPF is not running"
1211 return errormsg
1212
1213 # To find neighbor ip type
1214 ospf_summary_data = input_dict
1215 for ospf_summ, summ_data in ospf_summary_data.items():
1216 if ospf_summ not in show_ospf_json:
1217 continue
701a0192 1218 summary = ospf_summary_data[ospf_summ]["Summary address"]
4256a209 1219 if summary in show_ospf_json:
1220 for summ in summ_data:
1221 if summ_data[summ] == show_ospf_json[summary][summ]:
701a0192 1222 logger.info(
1223 "[DUT: %s] OSPF summary %s:%s is %s",
1224 router,
1225 summary,
1226 summ,
1227 summ_data[summ],
1228 )
4256a209 1229 result = True
1230 else:
701a0192 1231 errormsg = (
1232 "[DUT: {}] OSPF summary {}:{} is %s, "
1233 "Expected is {}".format(
1234 router, summary, summ, show_ospf_json[summary][summ]
1235 )
1236 )
4256a209 1237 return errormsg
1238
1239 logger.debug("Exiting API: verify_ospf_summary()")
1240 return result