]> git.proxmox.com Git - mirror_frr.git/blame - tests/topotests/lib/ospf.py
ospfd: addition of OSPF_LOG.
[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
2448d002 21import ipaddress
22import sys
2448d002 23from copy import deepcopy
49581587 24
4256a209 25# Import common_config to use commomnly used APIs
701a0192 26from lib.common_config import (
4f99894d 27 create_common_configurations,
701a0192 28 InvalidCLIError,
49581587
CH
29 generate_ips,
30 retry,
701a0192 31 run_frr_cmd,
49581587 32 validate_ip_address,
701a0192 33)
49581587
CH
34from lib.topolog import logger
35from lib.topotest import frr_unicode
4256a209 36
37################################
38# Configure procs
39################################
40
701a0192 41
49581587 42def create_router_ospf(tgen, topo=None, input_dict=None, build=False, load_config=True):
4256a209 43 """
44 API to configure ospf on router.
45
46 Parameters
47 ----------
48 * `tgen` : Topogen object
49 * `topo` : json file data
50 * `input_dict` : Input dict data, required when configuring from testcase
51 * `build` : Only for initial setup phase this is set as True.
52 * `load_config` : Loading the config to router this is set as True.
53
54 Usage
55 -----
56 input_dict = {
57 "r1": {
58 "ospf": {
59 "router_id": "22.22.22.22",
9458be1a 60 "area": [{ "id": "0.0.0.0", "type": "nssa"}]
4256a209 61 }
62 }
63
64 result = create_router_ospf(tgen, topo, input_dict)
65
66 Returns
67 -------
68 True or False
69 """
70 logger.debug("Entering lib API: create_router_ospf()")
71 result = False
72
49581587
CH
73 if topo is None:
74 topo = tgen.json_topo
75
4256a209 76 if not input_dict:
77 input_dict = deepcopy(topo)
78 else:
79 topo = topo["routers"]
80 input_dict = deepcopy(input_dict)
81
4f99894d
CH
82 for ospf in ["ospf", "ospf6"]:
83 config_data_dict = {}
4256a209 84
4f99894d
CH
85 for router in input_dict.keys():
86 if ospf not in input_dict[router]:
87 logger.debug("Router %s: %s not present in input_dict", router, ospf)
88 continue
2448d002 89
4f99894d
CH
90 config_data = __create_ospf_global(
91 tgen, input_dict, router, build, load_config, ospf
92 )
93 if config_data:
94 if router not in config_data_dict:
95 config_data_dict[router] = config_data
96 else:
97 config_data_dict[router].extend(config_data)
98 try:
99 result = create_common_configurations(
100 tgen, config_data_dict, ospf, build, load_config
101 )
102 except InvalidCLIError:
103 logger.error("create_router_ospf (ipv4)", exc_info=True)
104 result = False
2448d002 105
4256a209 106 logger.debug("Exiting lib API: create_router_ospf()")
107 return result
108
109
a53c08bc 110def __create_ospf_global(tgen, input_dict, router, build, load_config, ospf):
4256a209 111 """
112 Helper API to create ospf global configuration.
113
114 Parameters
115 ----------
116 * `tgen` : Topogen object
117 * `input_dict` : Input dict data, required when configuring from testcase
118 * `router` : router to be configured.
119 * `build` : Only for initial setup phase this is set as True.
120 * `load_config` : Loading the config to router this is set as True.
889da676 121 * `ospf` : either 'ospf' or 'ospf6'
4256a209 122
2718dd02 123 Usage
124 -----
125 input_dict = {
126 "routers": {
127 "r1": {
128 "links": {
129 "r3": {
130 "ipv6": "2013:13::1/64",
4f99894d 131 "ospf6": {
2718dd02 132 "hello_interval": 1,
133 "dead_interval": 4,
134 "network": "point-to-point"
135 }
4f99894d 136 }
2718dd02 137 },
138 "ospf6": {
139 "router_id": "1.1.1.1",
140 "neighbors": {
141 "r3": {
142 "area": "1.1.1.1"
143 }
144 }
145 }
146 }
147 }
148
4256a209 149 Returns
150 -------
4f99894d 151 list of configuration commands
4256a209 152 """
153
4f99894d 154 config_data = []
4256a209 155
4f99894d
CH
156 if ospf not in input_dict[router]:
157 return config_data
4256a209 158
4f99894d 159 logger.debug("Entering lib API: __create_ospf_global()")
4256a209 160
4f99894d
CH
161 ospf_data = input_dict[router][ospf]
162 del_ospf_action = ospf_data.setdefault("delete", False)
163 if del_ospf_action:
164 config_data = ["no router {}".format(ospf)]
165 return config_data
166
167 cmd = "router {}".format(ospf)
168
169 config_data.append(cmd)
170
171 # router id
172 router_id = ospf_data.setdefault("router_id", None)
173 del_router_id = ospf_data.setdefault("del_router_id", False)
174 if del_router_id:
175 config_data.append("no {} router-id".format(ospf))
176 if router_id:
177 config_data.append("{} router-id {}".format(ospf, router_id))
178
179 # log-adjacency-changes
180 log_adj_changes = ospf_data.setdefault("log_adj_changes", None)
181 del_log_adj_changes = ospf_data.setdefault("del_log_adj_changes", False)
182 if del_log_adj_changes:
183 config_data.append("no log-adjacency-changes detail")
184 if log_adj_changes:
a53c08bc 185 config_data.append("log-adjacency-changes {}".format(log_adj_changes))
4f99894d
CH
186
187 # aggregation timer
188 aggr_timer = ospf_data.setdefault("aggr_timer", None)
189 del_aggr_timer = ospf_data.setdefault("del_aggr_timer", False)
190 if del_aggr_timer:
191 config_data.append("no aggregation timer")
192 if aggr_timer:
a53c08bc 193 config_data.append("aggregation timer {}".format(aggr_timer))
4f99894d
CH
194
195 # maximum path information
196 ecmp_data = ospf_data.setdefault("maximum-paths", {})
197 if ecmp_data:
198 cmd = "maximum-paths {}".format(ecmp_data)
199 del_action = ospf_data.setdefault("del_max_path", False)
200 if del_action:
201 cmd = "no maximum-paths"
4256a209 202 config_data.append(cmd)
203
4f99894d
CH
204 # redistribute command
205 redistribute_data = ospf_data.setdefault("redistribute", {})
206 if redistribute_data:
207 for redistribute in redistribute_data:
208 if "redist_type" not in redistribute:
209 logger.debug(
210 "Router %s: 'redist_type' not present in " "input_dict", router
211 )
212 else:
213 cmd = "redistribute {}".format(redistribute["redist_type"])
214 for red_type in redistribute_data:
215 if "route_map" in red_type:
216 cmd = cmd + " route-map {}".format(red_type["route_map"])
217 del_action = redistribute.setdefault("delete", False)
218 if del_action:
219 cmd = "no {}".format(cmd)
220 config_data.append(cmd)
2448d002 221
4f99894d
CH
222 # area information
223 area_data = ospf_data.setdefault("area", {})
224 if area_data:
225 for area in area_data:
226 if "id" not in area:
227 logger.debug(
228 "Router %s: 'area id' not present in " "input_dict", router
229 )
230 else:
231 cmd = "area {}".format(area["id"])
889da676 232
4f99894d
CH
233 if "type" in area:
234 cmd = cmd + " {}".format(area["type"])
4256a209 235
4f99894d
CH
236 del_action = area.setdefault("delete", False)
237 if del_action:
238 cmd = "no {}".format(cmd)
239 config_data.append(cmd)
4256a209 240
a53c08bc 241 # def route information
4f99894d
CH
242 def_rte_data = ospf_data.setdefault("default-information", {})
243 if def_rte_data:
244 if "originate" not in def_rte_data:
a53c08bc
CH
245 logger.debug(
246 "Router %s: 'originate key' not present in " "input_dict", router
247 )
4f99894d
CH
248 else:
249 cmd = "default-information originate"
4256a209 250
4f99894d
CH
251 if "always" in def_rte_data:
252 cmd = cmd + " always"
2448d002 253
4f99894d
CH
254 if "metric" in def_rte_data:
255 cmd = cmd + " metric {}".format(def_rte_data["metric"])
2448d002 256
4f99894d 257 if "metric-type" in def_rte_data:
a53c08bc 258 cmd = cmd + " metric-type {}".format(def_rte_data["metric-type"])
2448d002 259
4f99894d
CH
260 if "route-map" in def_rte_data:
261 cmd = cmd + " route-map {}".format(def_rte_data["route-map"])
2448d002 262
4f99894d
CH
263 del_action = def_rte_data.setdefault("delete", False)
264 if del_action:
265 cmd = "no {}".format(cmd)
266 config_data.append(cmd)
2448d002 267
4f99894d
CH
268 # summary information
269 summary_data = ospf_data.setdefault("summary-address", {})
270 if summary_data:
271 for summary in summary_data:
272 if "prefix" not in summary:
273 logger.debug(
274 "Router %s: 'summary-address' not present in " "input_dict",
275 router,
276 )
277 else:
278 cmd = "summary {}/{}".format(summary["prefix"], summary["mask"])
4256a209 279
4f99894d
CH
280 _tag = summary.setdefault("tag", None)
281 if _tag:
282 cmd = "{} tag {}".format(cmd, _tag)
889da676 283
4f99894d
CH
284 _advertise = summary.setdefault("advertise", True)
285 if not _advertise:
286 cmd = "{} no-advertise".format(cmd)
cc90defc 287
4f99894d
CH
288 del_action = summary.setdefault("delete", False)
289 if del_action:
cc90defc 290 cmd = "no {}".format(cmd)
291 config_data.append(cmd)
292
4f99894d
CH
293 # ospf gr information
294 gr_data = ospf_data.setdefault("graceful-restart", {})
295 if gr_data:
296
297 if "opaque" in gr_data and gr_data["opaque"]:
298 cmd = "capability opaque"
299 if gr_data.setdefault("delete", False):
300 cmd = "no {}".format(cmd)
301 config_data.append(cmd)
302
859bce81
RW
303 if "helper enable" in gr_data and not gr_data["helper enable"]:
304 cmd = "graceful-restart helper enable"
4f99894d
CH
305 if gr_data.setdefault("delete", False):
306 cmd = "no {}".format(cmd)
307 config_data.append(cmd)
859bce81
RW
308 elif "helper enable" in gr_data and type(gr_data["helper enable"]) is list:
309 for rtrs in gr_data["helper enable"]:
310 cmd = "graceful-restart helper enable {}".format(rtrs)
cc90defc 311 if gr_data.setdefault("delete", False):
312 cmd = "no {}".format(cmd)
313 config_data.append(cmd)
cc90defc 314
4f99894d
CH
315 if "helper" in gr_data:
316 if type(gr_data["helper"]) is not list:
317 gr_data["helper"] = list(gr_data["helper"])
318 for helper_role in gr_data["helper"]:
319 cmd = "graceful-restart helper {}".format(helper_role)
cc90defc 320 if gr_data.setdefault("delete", False):
321 cmd = "no {}".format(cmd)
322 config_data.append(cmd)
323
4f99894d
CH
324 if "supported-grace-time" in gr_data:
325 cmd = "graceful-restart helper supported-grace-time {}".format(
326 gr_data["supported-grace-time"]
327 )
328 if gr_data.setdefault("delete", False):
329 cmd = "no {}".format(cmd)
330 config_data.append(cmd)
4256a209 331
332 logger.debug("Exiting lib API: create_ospf_global()")
4f99894d
CH
333
334 return config_data
4256a209 335
336
a53c08bc
CH
337def config_ospf_interface(
338 tgen, topo=None, input_dict=None, build=False, load_config=True
339):
4256a209 340 """
341 API to configure ospf on router.
342
343 Parameters
344 ----------
345 * `tgen` : Topogen object
346 * `topo` : json file data
347 * `input_dict` : Input dict data, required when configuring from testcase
348 * `build` : Only for initial setup phase this is set as True.
349 * `load_config` : Loading the config to router this is set as True.
350
351 Usage
352 -----
353 r1_ospf_auth = {
354 "r1": {
355 "links": {
356 "r2": {
357 "ospf": {
9458be1a 358 "authentication": "message-digest",
4256a209 359 "authentication-key": "ospf",
360 "message-digest-key": "10"
361 }
362 }
363 }
364 }
365 }
366 result = config_ospf_interface(tgen, topo, r1_ospf_auth)
367
368 Returns
369 -------
370 True or False
371 """
372 logger.debug("Enter lib config_ospf_interface")
db56171c 373 result = False
49581587
CH
374
375 if topo is None:
376 topo = tgen.json_topo
377
4256a209 378 if not input_dict:
379 input_dict = deepcopy(topo)
380 else:
381 input_dict = deepcopy(input_dict)
4f99894d
CH
382
383 config_data_dict = {}
384
4256a209 385 for router in input_dict.keys():
386 config_data = []
701a0192 387 for lnk in input_dict[router]["links"].keys():
388 if "ospf" not in input_dict[router]["links"][lnk]:
389 logger.debug(
0b25370e 390 "Router %s: ospf config is not present in" "input_dict", router
701a0192 391 )
4256a209 392 continue
701a0192 393 ospf_data = input_dict[router]["links"][lnk]["ospf"]
4256a209 394 data_ospf_area = ospf_data.setdefault("area", None)
395 data_ospf_auth = ospf_data.setdefault("authentication", None)
396 data_ospf_dr_priority = ospf_data.setdefault("priority", None)
397 data_ospf_cost = ospf_data.setdefault("cost", None)
8694dd78 398 data_ospf_mtu = ospf_data.setdefault("mtu_ignore", None)
4256a209 399
400 try:
701a0192 401 intf = topo["routers"][router]["links"][lnk]["interface"]
4256a209 402 except KeyError:
701a0192 403 intf = topo["switches"][router]["links"][lnk]["interface"]
4256a209 404
405 # interface
406 cmd = "interface {}".format(intf)
407
408 config_data.append(cmd)
409 # interface area config
410 if data_ospf_area:
411 cmd = "ip ospf area {}".format(data_ospf_area)
412 config_data.append(cmd)
9458be1a 413
4256a209 414 # interface ospf auth
415 if data_ospf_auth:
701a0192 416 if data_ospf_auth == "null":
4256a209 417 cmd = "ip ospf authentication null"
701a0192 418 elif data_ospf_auth == "message-digest":
4256a209 419 cmd = "ip ospf authentication message-digest"
420 else:
421 cmd = "ip ospf authentication"
422
701a0192 423 if "del_action" in ospf_data:
4256a209 424 cmd = "no {}".format(cmd)
425 config_data.append(cmd)
426
427 if "message-digest-key" in ospf_data:
428 cmd = "ip ospf message-digest-key {} md5 {}".format(
701a0192 429 ospf_data["message-digest-key"], ospf_data["authentication-key"]
430 )
431 if "del_action" in ospf_data:
4256a209 432 cmd = "no {}".format(cmd)
433 config_data.append(cmd)
434
701a0192 435 if (
436 "authentication-key" in ospf_data
437 and "message-digest-key" not in ospf_data
438 ):
439 cmd = "ip ospf authentication-key {}".format(
440 ospf_data["authentication-key"]
441 )
442 if "del_action" in ospf_data:
4256a209 443 cmd = "no {}".format(cmd)
444 config_data.append(cmd)
445
446 # interface ospf dr priority
8694dd78 447 if data_ospf_dr_priority:
701a0192 448 cmd = "ip ospf priority {}".format(ospf_data["priority"])
449 if "del_action" in ospf_data:
4256a209 450 cmd = "no {}".format(cmd)
451 config_data.append(cmd)
452
453 # interface ospf cost
8694dd78 454 if data_ospf_cost:
701a0192 455 cmd = "ip ospf cost {}".format(ospf_data["cost"])
456 if "del_action" in ospf_data:
4256a209 457 cmd = "no {}".format(cmd)
458 config_data.append(cmd)
459
8694dd78 460 # interface ospf mtu
461 if data_ospf_mtu:
462 cmd = "ip ospf mtu-ignore"
db56171c 463 if "del_action" in ospf_data:
8694dd78 464 cmd = "no {}".format(cmd)
465 config_data.append(cmd)
466
4256a209 467 if build:
468 return config_data
4f99894d
CH
469
470 if config_data:
471 config_data_dict[router] = config_data
472
473 result = create_common_configurations(
474 tgen, config_data_dict, "interface_config", build=build
475 )
476
2448d002 477 logger.debug("Exiting lib API: config_ospf_interface()")
4256a209 478 return result
479
701a0192 480
2448d002 481def clear_ospf(tgen, router, ospf=None):
4256a209 482 """
483 This API is to clear ospf neighborship by running
484 clear ip ospf interface * command,
485
486 Parameters
487 ----------
488 * `tgen`: topogen object
489 * `router`: device under test
490
491 Usage
492 -----
493 clear_ospf(tgen, "r1")
494 """
495
496 logger.debug("Entering lib API: clear_ospf()")
497 if router not in tgen.routers():
498 return False
499
500 rnode = tgen.routers()[router]
4256a209 501 # Clearing OSPF
2448d002 502 if ospf:
503 version = "ipv6"
504 else:
505 version = "ip"
4256a209 506
2448d002 507 cmd = "clear {} ospf interface".format(version)
db56171c 508 logger.info("Clearing ospf process on router %s.. using command '%s'", router, cmd)
2448d002 509 run_frr_cmd(rnode, cmd)
4256a209 510
511 logger.debug("Exiting lib API: clear_ospf()")
512
513
88b7d3e7 514def redistribute_ospf(tgen, topo, dut, route_type, **kwargs):
515 """
516 Redstribution of routes inside ospf.
517
518 Parameters
519 ----------
520 * `tgen`: Topogen object
521 * `topo` : json file data
522 * `dut`: device under test
523 * `route_type`: "static" or "connected" or ....
524 * `kwargs`: pass extra information (see below)
525
526 Usage
527 -----
528 redistribute_ospf(tgen, topo, "r0", "static", delete=True)
529 redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
530 """
531
532 ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": route_type}]}}}
533 for k, v in kwargs.items():
534 ospf_red[dut]["ospf"]["redistribute"][0][k] = v
535
536 result = create_router_ospf(tgen, topo, ospf_red)
537 assert result is True, "Testcase : Failed \n Error: {}".format(result)
538
539
4256a209 540################################
541# Verification procs
542################################
ed776e38 543@retry(retry_timeout=80)
a53c08bc
CH
544def verify_ospf_neighbor(
545 tgen, topo=None, dut=None, input_dict=None, lan=False, expected=True
546):
4256a209 547 """
548 This API is to verify ospf neighborship by running
549 show ip ospf neighbour command,
550
551 Parameters
552 ----------
553 * `tgen` : Topogen object
554 * `topo` : json file data
555 * `dut`: device under test
556 * `input_dict` : Input dict data, required when configuring from testcase
557 * `lan` : verify neighbors in lan topology
3c41ebf8 558 * `expected` : expected results from API, by-default True
4256a209 559
560 Usage
561 -----
562 1. To check FULL neighbors.
563 verify_ospf_neighbor(tgen, topo, dut=dut)
564
565 2. To check neighbors with their roles.
566 input_dict = {
567 "r0": {
568 "ospf": {
569 "neighbors": {
570 "r1": {
571 "state": "Full",
572 "role": "DR"
573 },
574 "r2": {
575 "state": "Full",
576 "role": "DROther"
577 },
578 "r3": {
579 "state": "Full",
580 "role": "DROther"
581 }
582 }
583 }
584 }
585 }
586 result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
587
588 Returns
589 -------
590 True or False (Error Message)
591 """
592 logger.debug("Entering lib API: verify_ospf_neighbor()")
593 result = False
49581587
CH
594 if topo is None:
595 topo = tgen.json_topo
596
4256a209 597 if input_dict:
11761ab0 598 for router, rnode in tgen.routers().items():
701a0192 599 if "ospf" not in topo["routers"][router]:
4256a209 600 continue
601
602 if dut is not None and dut != router:
603 continue
604
605 logger.info("Verifying OSPF neighborship on router %s:", router)
701a0192 606 show_ospf_json = run_frr_cmd(
9458be1a 607 rnode, "show ip ospf neighbor all json", isjson=True
701a0192 608 )
4256a209 609
610 # Verifying output dictionary show_ospf_json is empty or not
611 if not bool(show_ospf_json):
612 errormsg = "OSPF is not running"
613 return errormsg
614
615 ospf_data_list = input_dict[router]["ospf"]
701a0192 616 ospf_nbr_list = ospf_data_list["neighbors"]
4256a209 617
618 for ospf_nbr, nbr_data in ospf_nbr_list.items():
701a0192 619 data_ip = topo["routers"][ospf_nbr]["links"]
620 data_rid = topo["routers"][ospf_nbr]["ospf"]["router_id"]
4256a209 621 if ospf_nbr in data_ip:
622 nbr_details = nbr_data[ospf_nbr]
623 elif lan:
701a0192 624 for switch in topo["switches"]:
625 if "ospf" in topo["switches"][switch]["links"][router]:
626 neighbor_ip = data_ip[switch]["ipv4"].split("/")[0]
4256a209 627 else:
628 continue
629 else:
701a0192 630 neighbor_ip = data_ip[router]["ipv4"].split("/")[0]
4256a209 631
632 nh_state = None
633 neighbor_ip = neighbor_ip.lower()
634 nbr_rid = data_rid
635 try:
701a0192 636 nh_state = show_ospf_json[nbr_rid][0]["state"].split("/")[0]
637 intf_state = show_ospf_json[nbr_rid][0]["state"].split("/")[1]
4256a209 638 except KeyError:
701a0192 639 errormsg = "[DUT: {}] OSPF peer {} missing".format(router, nbr_rid)
4256a209 640 return errormsg
641
701a0192 642 nbr_state = nbr_data.setdefault("state", None)
643 nbr_role = nbr_data.setdefault("role", None)
4256a209 644
645 if nbr_state:
646 if nbr_state == nh_state:
701a0192 647 logger.info(
648 "[DUT: {}] OSPF Nbr is {}:{} State {}".format(
649 router, ospf_nbr, nbr_rid, nh_state
650 )
651 )
4256a209 652 result = True
653 else:
701a0192 654 errormsg = (
655 "[DUT: {}] OSPF is not Converged, neighbor"
656 " state is {}".format(router, nh_state)
657 )
4256a209 658 return errormsg
659 if nbr_role:
660 if nbr_role == intf_state:
701a0192 661 logger.info(
662 "[DUT: {}] OSPF Nbr is {}: {} Role {}".format(
663 router, ospf_nbr, nbr_rid, nbr_role
664 )
665 )
4256a209 666 else:
701a0192 667 errormsg = (
668 "[DUT: {}] OSPF is not Converged with rid"
669 "{}, role is {}".format(router, nbr_rid, intf_state)
670 )
4256a209 671 return errormsg
672 continue
673 else:
11761ab0 674 for router, rnode in tgen.routers().items():
701a0192 675 if "ospf" not in topo["routers"][router]:
4256a209 676 continue
677
678 if dut is not None and dut != router:
679 continue
680
681 logger.info("Verifying OSPF neighborship on router %s:", router)
701a0192 682 show_ospf_json = run_frr_cmd(
683 rnode, "show ip ospf neighbor all json", isjson=True
684 )
4256a209 685 # Verifying output dictionary show_ospf_json is empty or not
686 if not bool(show_ospf_json):
687 errormsg = "OSPF is not running"
688 return errormsg
689
690 ospf_data_list = topo["routers"][router]["ospf"]
701a0192 691 ospf_neighbors = ospf_data_list["neighbors"]
4256a209 692 total_peer = 0
693 total_peer = len(ospf_neighbors.keys())
694 no_of_ospf_nbr = 0
701a0192 695 ospf_nbr_list = ospf_data_list["neighbors"]
4256a209 696 no_of_peer = 0
697 for ospf_nbr, nbr_data in ospf_nbr_list.items():
698 if nbr_data:
701a0192 699 data_ip = topo["routers"][nbr_data["nbr"]]["links"]
700 data_rid = topo["routers"][nbr_data["nbr"]]["ospf"]["router_id"]
4256a209 701 else:
701a0192 702 data_ip = topo["routers"][ospf_nbr]["links"]
703 data_rid = topo["routers"][ospf_nbr]["ospf"]["router_id"]
4256a209 704 if ospf_nbr in data_ip:
705 nbr_details = nbr_data[ospf_nbr]
706 elif lan:
701a0192 707 for switch in topo["switches"]:
708 if "ospf" in topo["switches"][switch]["links"][router]:
709 neighbor_ip = data_ip[switch]["ipv4"].split("/")[0]
4256a209 710 else:
711 continue
712 else:
701a0192 713 neighbor_ip = data_ip[router]["ipv4"].split("/")[0]
4256a209 714
715 nh_state = None
716 neighbor_ip = neighbor_ip.lower()
717 nbr_rid = data_rid
718 try:
701a0192 719 nh_state = show_ospf_json[nbr_rid][0]["state"].split("/")[0]
4256a209 720 except KeyError:
701a0192 721 errormsg = "[DUT: {}] OSPF peer {} missing,from " "{} ".format(
722 router, nbr_rid, ospf_nbr
723 )
4256a209 724 return errormsg
725
701a0192 726 if nh_state == "Full":
4256a209 727 no_of_peer += 1
728
729 if no_of_peer == total_peer:
730 logger.info("[DUT: {}] OSPF is Converged".format(router))
731 result = True
732 else:
701a0192 733 errormsg = "[DUT: {}] OSPF is not Converged".format(router)
4256a209 734 return errormsg
735
736 logger.debug("Exiting API: verify_ospf_neighbor()")
737 return result
738
701a0192 739
1feb577c 740################################
741# Verification procs
742################################
db56171c 743@retry(retry_timeout=50)
49581587 744def verify_ospf6_neighbor(tgen, topo=None, dut=None, input_dict=None, lan=False):
1feb577c 745 """
746 This API is to verify ospf neighborship by running
2448d002 747 show ipv6 ospf neighbour command,
1feb577c 748
749 Parameters
750 ----------
751 * `tgen` : Topogen object
752 * `topo` : json file data
2448d002 753 * `dut`: device under test
754 * `input_dict` : Input dict data, required when configuring from testcase
755 * `lan` : verify neighbors in lan topology
1feb577c 756
757 Usage
758 -----
2448d002 759 1. To check FULL neighbors.
760 verify_ospf_neighbor(tgen, topo, dut=dut)
1feb577c 761
2448d002 762 2. To check neighbors with their roles.
763 input_dict = {
764 "r0": {
765 "ospf6": {
766 "neighbors": {
767 "r1": {
768 "state": "Full",
769 "role": "DR"
770 },
771 "r2": {
772 "state": "Full",
773 "role": "DROther"
774 },
775 "r3": {
776 "state": "Full",
777 "role": "DROther"
778 }
779 }
780 }
781 }
782 }
783 result = verify_ospf6_neighbor(tgen, topo, dut, input_dict, lan=True)
1feb577c 784
96c715f3 785 3. To check there are no neighbors.
786 input_dict = {
787 "r0": {
788 "ospf6": {
789 "neighbors": []
790 }
791 }
792 }
793 result = verify_ospf6_neighbor(tgen, topo, dut, input_dict)
794
1feb577c 795 Returns
796 -------
797 True or False (Error Message)
798 """
2448d002 799 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1feb577c 800 result = False
1feb577c 801
49581587
CH
802 if topo is None:
803 topo = tgen.json_topo
804
2448d002 805 if input_dict:
806 for router, rnode in tgen.routers().items():
db56171c 807 if "ospf6" not in topo["routers"][router]:
2448d002 808 continue
1feb577c 809
2448d002 810 if dut is not None and dut != router:
811 continue
812
813 logger.info("Verifying OSPF neighborship on router %s:", router)
db56171c 814 show_ospf_json = run_frr_cmd(
815 rnode, "show ipv6 ospf neighbor json", isjson=True
816 )
2448d002 817 # Verifying output dictionary show_ospf_json is empty or not
818 if not bool(show_ospf_json):
819 errormsg = "OSPF6 is not running"
820 return errormsg
821
822 ospf_data_list = input_dict[router]["ospf6"]
db56171c 823 ospf_nbr_list = ospf_data_list["neighbors"]
2448d002 824
96c715f3 825 # Check if looking for no neighbors
826 if ospf_nbr_list == []:
827 if show_ospf_json["neighbors"] == []:
828 logger.info("[DUT: {}] OSPF6 no neighbors found".format(router))
829 return True
830 else:
831 errormsg = (
832 "[DUT: {}] OSPF6 active neighbors found, expected None".format(
833 router
834 )
835 )
836 return errormsg
837
2448d002 838 for ospf_nbr, nbr_data in ospf_nbr_list.items():
db56171c 839
840 try:
841 data_ip = data_rid = topo["routers"][ospf_nbr]["ospf6"]["router_id"]
842 except KeyError:
843 data_ip = data_rid = topo["routers"][nbr_data["nbr"]]["ospf6"][
844 "router_id"
845 ]
846
2448d002 847 if ospf_nbr in data_ip:
848 nbr_details = nbr_data[ospf_nbr]
849 elif lan:
db56171c 850 for switch in topo["switches"]:
851 if "ospf6" in topo["switches"][switch]["links"][router]:
2448d002 852 neighbor_ip = data_ip
853 else:
854 continue
855 else:
db56171c 856 neighbor_ip = data_ip[router]["ipv6"].split("/")[0]
2448d002 857
858 nh_state = None
859 neighbor_ip = neighbor_ip.lower()
860 nbr_rid = data_rid
db56171c 861 get_index_val = dict(
862 (d["neighborId"], dict(d, index=index))
863 for (index, d) in enumerate(show_ospf_json["neighbors"])
864 )
2448d002 865 try:
db56171c 866 nh_state = get_index_val.get(neighbor_ip)["state"]
867 intf_state = get_index_val.get(neighbor_ip)["ifState"]
2448d002 868 except TypeError:
db56171c 869 errormsg = "[DUT: {}] OSPF peer {} missing,from " "{} ".format(
870 router, nbr_rid, ospf_nbr
871 )
2448d002 872 return errormsg
873
db56171c 874 nbr_state = nbr_data.setdefault("state", None)
875 nbr_role = nbr_data.setdefault("role", None)
2448d002 876
877 if nbr_state:
878 if nbr_state == nh_state:
db56171c 879 logger.info(
880 "[DUT: {}] OSPF6 Nbr is {}:{} State {}".format(
881 router, ospf_nbr, nbr_rid, nh_state
882 )
883 )
2448d002 884 result = True
885 else:
db56171c 886 errormsg = (
887 "[DUT: {}] OSPF6 is not Converged, neighbor"
888 " state is {} , Expected state is {}".format(
889 router, nh_state, nbr_state
890 )
891 )
2448d002 892 return errormsg
893 if nbr_role:
894 if nbr_role == intf_state:
db56171c 895 logger.info(
896 "[DUT: {}] OSPF6 Nbr is {}: {} Role {}".format(
897 router, ospf_nbr, nbr_rid, nbr_role
898 )
899 )
2448d002 900 else:
db56171c 901 errormsg = (
902 "[DUT: {}] OSPF6 is not Converged with rid"
903 "{}, role is {}, Expected role is {}".format(
904 router, nbr_rid, intf_state, nbr_role
905 )
906 )
2448d002 907 return errormsg
908 continue
909 else:
910
911 for router, rnode in tgen.routers().items():
db56171c 912 if "ospf6" not in topo["routers"][router]:
2448d002 913 continue
914
915 if dut is not None and dut != router:
916 continue
917
918 logger.info("Verifying OSPF6 neighborship on router %s:", router)
db56171c 919 show_ospf_json = run_frr_cmd(
920 rnode, "show ipv6 ospf neighbor json", isjson=True
921 )
2448d002 922 # Verifying output dictionary show_ospf_json is empty or not
923 if not bool(show_ospf_json):
924 errormsg = "OSPF6 is not running"
925 return errormsg
926
927 ospf_data_list = topo["routers"][router]["ospf6"]
db56171c 928 ospf_neighbors = ospf_data_list["neighbors"]
2448d002 929 total_peer = 0
930 total_peer = len(ospf_neighbors.keys())
931 no_of_ospf_nbr = 0
db56171c 932 ospf_nbr_list = ospf_data_list["neighbors"]
2448d002 933 no_of_peer = 0
934 for ospf_nbr, nbr_data in ospf_nbr_list.items():
db56171c 935 try:
936 data_ip = data_rid = topo["routers"][ospf_nbr]["ospf6"]["router_id"]
937 except KeyError:
938 data_ip = data_rid = topo["routers"][nbr_data["nbr"]]["ospf6"][
939 "router_id"
940 ]
941
2448d002 942 if ospf_nbr in data_ip:
943 nbr_details = nbr_data[ospf_nbr]
944 elif lan:
db56171c 945 for switch in topo["switches"]:
946 if "ospf6" in topo["switches"][switch]["links"][router]:
2448d002 947 neighbor_ip = data_ip
948 else:
949 continue
950 else:
951 neighbor_ip = data_ip
952
953 nh_state = None
954 neighbor_ip = neighbor_ip.lower()
955 nbr_rid = data_rid
db56171c 956 get_index_val = dict(
957 (d["neighborId"], dict(d, index=index))
958 for (index, d) in enumerate(show_ospf_json["neighbors"])
959 )
2448d002 960 try:
db56171c 961 nh_state = get_index_val.get(neighbor_ip)["state"]
962 intf_state = get_index_val.get(neighbor_ip)["ifState"]
2448d002 963 except TypeError:
db56171c 964 errormsg = "[DUT: {}] OSPF peer {} missing,from " "{} ".format(
965 router, nbr_rid, ospf_nbr
966 )
2448d002 967 return errormsg
1feb577c 968
db56171c 969 if nh_state == "Full":
2448d002 970 no_of_peer += 1
1feb577c 971
2448d002 972 if no_of_peer == total_peer:
973 logger.info("[DUT: {}] OSPF6 is Converged".format(router))
974 result = True
975 else:
db56171c 976 errormsg = "[DUT: {}] OSPF6 is not Converged".format(router)
2448d002 977 return errormsg
1feb577c 978
2448d002 979 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1feb577c 980 return result
981
982
ed776e38 983@retry(retry_timeout=40)
701a0192 984def verify_ospf_rib(
3c41ebf8 985 tgen, dut, input_dict, next_hop=None, tag=None, metric=None, fib=None, expected=True
701a0192 986):
4256a209 987 """
988 This API is to verify ospf routes by running
989 show ip ospf route command.
990
991 Parameters
992 ----------
993 * `tgen` : Topogen object
994 * `dut`: device under test
995 * `input_dict` : Input dict data, required when configuring from testcase
996 * `next_hop` : next to be verified
997 * `tag` : tag to be verified
998 * `metric` : metric to be verified
999 * `fib` : True if the route is installed in FIB.
3c41ebf8 1000 * `expected` : expected results from API, by-default True
4256a209 1001
1002 Usage
1003 -----
1004 input_dict = {
1005 "r1": {
1006 "static_routes": [
1007 {
1008 "network": ip_net,
1009 "no_of_ip": 1,
1010 "routeType": "N"
1011 }
1012 ]
1013 }
1014 }
1015
1016 result = verify_ospf_rib(tgen, dut, input_dict,next_hop=nh)
1017
1018 Returns
1019 -------
1020 True or False (Error Message)
1021 """
1022
1023 logger.info("Entering lib API: verify_ospf_rib()")
1024 result = False
1025 router_list = tgen.routers()
1026 additional_nexthops_in_required_nhs = []
1027 found_hops = []
1028 for routerInput in input_dict.keys():
11761ab0 1029 for router, rnode in router_list.items():
4256a209 1030 if router != dut:
1031 continue
1032
1033 logger.info("Checking router %s RIB:", router)
1034
1035 # Verifying RIB routes
1036 command = "show ip ospf route"
1037
1038 found_routes = []
1039 missing_routes = []
1040
701a0192 1041 if (
1042 "static_routes" in input_dict[routerInput]
1043 or "prefix" in input_dict[routerInput]
1044 ):
4256a209 1045 if "prefix" in input_dict[routerInput]:
1046 static_routes = input_dict[routerInput]["prefix"]
1047 else:
1048 static_routes = input_dict[routerInput]["static_routes"]
1049
4256a209 1050 for static_route in static_routes:
1051 cmd = "{}".format(command)
1052
1053 cmd = "{} json".format(cmd)
1054
701a0192 1055 ospf_rib_json = run_frr_cmd(rnode, cmd, isjson=True)
4256a209 1056
1057 # Verifying output dictionary ospf_rib_json is not empty
1058 if bool(ospf_rib_json) is False:
701a0192 1059 errormsg = (
1060 "[DUT: {}] No routes found in OSPF route "
4256a209 1061 "table".format(router)
701a0192 1062 )
4256a209 1063 return errormsg
1064
1065 network = static_route["network"]
1066 no_of_ip = static_route.setdefault("no_of_ip", 1)
1067 _tag = static_route.setdefault("tag", None)
1068 _rtype = static_route.setdefault("routeType", None)
1069
4256a209 1070 # Generating IPs for verification
1071 ip_list = generate_ips(network, no_of_ip)
1072 st_found = False
1073 nh_found = False
1074
1075 for st_rt in ip_list:
c8e5983d 1076 st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
4256a209 1077
1078 _addr_type = validate_ip_address(st_rt)
701a0192 1079 if _addr_type != "ipv4":
4256a209 1080 continue
1081
1082 if st_rt in ospf_rib_json:
1083 st_found = True
1084 found_routes.append(st_rt)
1085
1086 if fib and next_hop:
1087 if type(next_hop) is not list:
1088 next_hop = [next_hop]
1089
1090 for mnh in range(0, len(ospf_rib_json[st_rt])):
701a0192 1091 if (
1092 "fib"
1093 in ospf_rib_json[st_rt][mnh]["nexthops"][0]
1094 ):
1095 found_hops.append(
1096 [
1097 rib_r["ip"]
1098 for rib_r in ospf_rib_json[st_rt][mnh][
1099 "nexthops"
1100 ]
1101 ]
1102 )
4256a209 1103
1104 if found_hops[0]:
701a0192 1105 missing_list_of_nexthops = set(
1106 found_hops[0]
1107 ).difference(next_hop)
1108 additional_nexthops_in_required_nhs = set(
1109 next_hop
1110 ).difference(found_hops[0])
4256a209 1111
1112 if additional_nexthops_in_required_nhs:
1113 logger.info(
1114 "Nexthop "
1115 "%s is not active for route %s in "
1116 "RIB of router %s\n",
1117 additional_nexthops_in_required_nhs,
701a0192 1118 st_rt,
1119 dut,
1120 )
4256a209 1121 errormsg = (
1122 "Nexthop {} is not active"
1123 " for route {} in RIB of router"
1124 " {}\n".format(
701a0192 1125 additional_nexthops_in_required_nhs,
1126 st_rt,
1127 dut,
1128 )
1129 )
4256a209 1130 return errormsg
1131 else:
1132 nh_found = True
1133
1134 elif next_hop and fib is None:
1135 if type(next_hop) is not list:
1136 next_hop = [next_hop]
701a0192 1137 found_hops = [
1138 rib_r["ip"]
1139 for rib_r in ospf_rib_json[st_rt]["nexthops"]
1140 ]
4256a209 1141
1142 if found_hops:
701a0192 1143 missing_list_of_nexthops = set(
1144 found_hops
1145 ).difference(next_hop)
1146 additional_nexthops_in_required_nhs = set(
1147 next_hop
1148 ).difference(found_hops)
4256a209 1149
1150 if additional_nexthops_in_required_nhs:
1151 logger.info(
701a0192 1152 "Missing nexthop %s for route"
1153 " %s in RIB of router %s\n",
4256a209 1154 additional_nexthops_in_required_nhs,
701a0192 1155 st_rt,
1156 dut,
1157 )
1158 errormsg = (
1159 "Nexthop {} is Missing for "
1160 "route {} in RIB of router {}\n".format(
1161 additional_nexthops_in_required_nhs,
1162 st_rt,
1163 dut,
1164 )
1165 )
4256a209 1166 return errormsg
1167 else:
1168 nh_found = True
1169 if _rtype:
701a0192 1170 if "routeType" not in ospf_rib_json[st_rt]:
1171 errormsg = (
1172 "[DUT: {}]: routeType missing"
9458be1a 1173 " for route {} in OSPF RIB \n".format(
1174 dut, st_rt
1175 )
701a0192 1176 )
4256a209 1177 return errormsg
701a0192 1178 elif _rtype != ospf_rib_json[st_rt]["routeType"]:
1179 errormsg = (
1180 "[DUT: {}]: routeType mismatch"
9458be1a 1181 " for route {} in OSPF RIB \n".format(
1182 dut, st_rt
1183 )
701a0192 1184 )
4256a209 1185 return errormsg
1186 else:
701a0192 1187 logger.info(
9458be1a 1188 "[DUT: {}]: Found routeType {}"
1189 " for route {}".format(dut, _rtype, st_rt)
701a0192 1190 )
4256a209 1191 if tag:
701a0192 1192 if "tag" not in ospf_rib_json[st_rt]:
1193 errormsg = (
1194 "[DUT: {}]: tag is not"
1195 " present for"
1196 " route {} in RIB \n".format(dut, st_rt)
1197 )
4256a209 1198 return errormsg
1199
701a0192 1200 if _tag != ospf_rib_json[st_rt]["tag"]:
1201 errormsg = (
1202 "[DUT: {}]: tag value {}"
1203 " is not matched for"
9fa6ec14 1204 " route {} in RIB \n".format(
1205 dut,
1206 _tag,
1207 st_rt,
1208 )
701a0192 1209 )
4256a209 1210 return errormsg
1211
1212 if metric is not None:
701a0192 1213 if "type2cost" not in ospf_rib_json[st_rt]:
1214 errormsg = (
1215 "[DUT: {}]: metric is"
1216 " not present for"
1217 " route {} in RIB \n".format(dut, st_rt)
1218 )
4256a209 1219 return errormsg
1220
701a0192 1221 if metric != ospf_rib_json[st_rt]["type2cost"]:
1222 errormsg = (
1223 "[DUT: {}]: metric value "
1224 "{} is not matched for "
9fa6ec14 1225 "route {} in RIB \n".format(
1226 dut,
1227 metric,
1228 st_rt,
1229 )
701a0192 1230 )
4256a209 1231 return errormsg
1232
1233 else:
1234 missing_routes.append(st_rt)
1235
1236 if nh_found:
701a0192 1237 logger.info(
1238 "[DUT: {}]: Found next_hop {} for all OSPF"
1239 " routes in RIB".format(router, next_hop)
1240 )
4256a209 1241
1242 if len(missing_routes) > 0:
701a0192 1243 errormsg = "[DUT: {}]: Missing route in RIB, " "routes: {}".format(
1244 dut, missing_routes
1245 )
4256a209 1246 return errormsg
1247
1248 if found_routes:
701a0192 1249 logger.info(
1250 "[DUT: %s]: Verified routes in RIB, found" " routes are: %s\n",
1251 dut,
1252 found_routes,
1253 )
4256a209 1254 result = True
1255
1256 logger.info("Exiting lib API: verify_ospf_rib()")
1257 return result
1258
1259
ed776e38 1260@retry(retry_timeout=20)
a53c08bc
CH
1261def verify_ospf_interface(
1262 tgen, topo=None, dut=None, lan=False, input_dict=None, expected=True
1263):
4256a209 1264 """
1265 This API is to verify ospf routes by running
1266 show ip ospf interface command.
1267
1268 Parameters
1269 ----------
1270 * `tgen` : Topogen object
1271 * `topo` : topology descriptions
1272 * `dut`: device under test
1273 * `lan`: if set to true this interface belongs to LAN.
1274 * `input_dict` : Input dict data, required when configuring from testcase
3c41ebf8 1275 * `expected` : expected results from API, by-default True
4256a209 1276
1277 Usage
1278 -----
1279 input_dict= {
1280 'r0': {
1281 'links':{
1282 's1': {
1283 'ospf':{
1284 'priority':98,
1285 'timerDeadSecs': 4,
1286 'area': '0.0.0.3',
1287 'mcastMemberOspfDesignatedRouters': True,
1288 'mcastMemberOspfAllRouters': True,
1289 'ospfEnabled': True,
1290
1291 }
1292 }
1293 }
1294 }
1295 }
1296 result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
1297
1298 Returns
1299 -------
1300 True or False (Error Message)
1301 """
1302
1303 logger.debug("Entering lib API: verify_ospf_interface()")
1304 result = False
49581587
CH
1305 if topo is None:
1306 topo = tgen.json_topo
1307
11761ab0 1308 for router, rnode in tgen.routers().items():
701a0192 1309 if "ospf" not in topo["routers"][router]:
4256a209 1310 continue
1311
1312 if dut is not None and dut != router:
1313 continue
1314
1315 logger.info("Verifying OSPF interface on router %s:", router)
701a0192 1316 show_ospf_json = run_frr_cmd(rnode, "show ip ospf interface json", isjson=True)
4256a209 1317
1318 # Verifying output dictionary show_ospf_json is empty or not
1319 if not bool(show_ospf_json):
1320 errormsg = "OSPF is not running"
1321 return errormsg
1322
1323 # To find neighbor ip type
1324 ospf_intf_data = input_dict[router]["links"]
1325 for ospf_intf, intf_data in ospf_intf_data.items():
701a0192 1326 intf = topo["routers"][router]["links"][ospf_intf]["interface"]
1327 if intf in show_ospf_json["interfaces"]:
1328 for intf_attribute in intf_data["ospf"]:
1329 if (
1330 intf_data["ospf"][intf_attribute]
1331 == show_ospf_json["interfaces"][intf][intf_attribute]
1332 ):
1333 logger.info(
1334 "[DUT: %s] OSPF interface %s: %s is %s",
1335 router,
1336 intf,
1337 intf_attribute,
1338 intf_data["ospf"][intf_attribute],
1339 )
4256a209 1340 else:
701a0192 1341 errormsg = "[DUT: {}] OSPF interface {}: {} is {}, \
1342 Expected is {}".format(
1343 router,
1344 intf,
1345 intf_attribute,
1346 intf_data["ospf"][intf_attribute],
1347 show_ospf_json["interfaces"][intf][intf_attribute],
1348 )
4256a209 1349 return errormsg
1350 result = True
1351 logger.debug("Exiting API: verify_ospf_interface()")
1352 return result
1353
1354
ed776e38 1355@retry(retry_timeout=20)
3c41ebf8 1356def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
4256a209 1357 """
1358 This API is to verify ospf lsa's by running
1359 show ip ospf database command.
1360
1361 Parameters
1362 ----------
1363 * `tgen` : Topogen object
1364 * `dut`: device under test
1365 * `input_dict` : Input dict data, required when configuring from testcase
1366 * `topo` : next to be verified
3c41ebf8 1367 * `expected` : expected results from API, by-default True
4256a209 1368
1369 Usage
1370 -----
1371 input_dict = {
1372 "areas": {
1373 "0.0.0.0": {
1374 "Router Link States": {
1375 "100.1.1.0-100.1.1.0": {
1376 "LSID": "100.1.1.0",
1377 "Advertised router": "100.1.1.0",
1378 "LSA Age": 130,
1379 "Sequence Number": "80000006",
1380 "Checksum": "a703",
1381 "Router links": 3
1382 }
1383 },
1384 "Net Link States": {
1385 "10.0.0.2-100.1.1.1": {
1386 "LSID": "10.0.0.2",
1387 "Advertised router": "100.1.1.1",
1388 "LSA Age": 137,
1389 "Sequence Number": "80000001",
1390 "Checksum": "9583"
1391 }
1392 },
1393 },
1394 }
1395 }
1396 result = verify_ospf_database(tgen, topo, dut, input_dict)
1397
1398 Returns
1399 -------
1400 True or False (Error Message)
1401 """
1402
1403 result = False
1404 router = dut
1405 logger.debug("Entering lib API: verify_ospf_database()")
1406
701a0192 1407 if "ospf" not in topo["routers"][dut]:
1408 errormsg = "[DUT: {}] OSPF is not configured on the router.".format(dut)
4256a209 1409 return errormsg
1410
1411 rnode = tgen.routers()[dut]
1412
1413 logger.info("Verifying OSPF interface on router %s:", dut)
701a0192 1414 show_ospf_json = run_frr_cmd(rnode, "show ip ospf database json", isjson=True)
4256a209 1415 # Verifying output dictionary show_ospf_json is empty or not
1416 if not bool(show_ospf_json):
1417 errormsg = "OSPF is not running"
1418 return errormsg
1419
1420 # for inter and inter lsa's
1421 ospf_db_data = input_dict.setdefault("areas", None)
701a0192 1422 ospf_external_lsa = input_dict.setdefault("AS External Link States", None)
4256a209 1423 if ospf_db_data:
701a0192 1424 for ospf_area, area_lsa in ospf_db_data.items():
1425 if ospf_area in show_ospf_json["areas"]:
1426 if "Router Link States" in area_lsa:
1427 for lsa in area_lsa["Router Link States"]:
1428 if (
1429 lsa
1430 in show_ospf_json["areas"][ospf_area]["Router Link States"]
1431 ):
1432 logger.info(
1433 "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
1434 router,
1435 ospf_area,
1436 lsa,
1437 )
1438 result = True
1439 else:
1440 errormsg = (
1441 "[DUT: {}] OSPF LSDB area {}: expected"
4256a209 1442 " Router LSA is {}".format(router, ospf_area, lsa)
701a0192 1443 )
1444 return errormsg
1445 if "Net Link States" in area_lsa:
1446 for lsa in area_lsa["Net Link States"]:
1447 if lsa in show_ospf_json["areas"][ospf_area]["Net Link States"]:
1448 logger.info(
1449 "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
1450 router,
1451 ospf_area,
1452 lsa,
1453 )
1454 result = True
1455 else:
1456 errormsg = (
1457 "[DUT: {}] OSPF LSDB area {}: expected"
4256a209 1458 " Network LSA is {}".format(router, ospf_area, lsa)
701a0192 1459 )
1460 return errormsg
1461 if "Summary Link States" in area_lsa:
1462 for lsa in area_lsa["Summary Link States"]:
1463 if (
1464 lsa
1465 in show_ospf_json["areas"][ospf_area]["Summary Link States"]
1466 ):
1467 logger.info(
1468 "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
1469 router,
1470 ospf_area,
1471 lsa,
1472 )
1473 result = True
1474 else:
1475 errormsg = (
1476 "[DUT: {}] OSPF LSDB area {}: expected"
4256a209 1477 " Summary LSA is {}".format(router, ospf_area, lsa)
701a0192 1478 )
1479 return errormsg
1480 if "ASBR-Summary Link States" in area_lsa:
1481 for lsa in area_lsa["ASBR-Summary Link States"]:
1482 if (
1483 lsa
1484 in show_ospf_json["areas"][ospf_area][
1485 "ASBR-Summary Link States"
1486 ]
1487 ):
1488 logger.info(
1489 "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
1490 router,
1491 ospf_area,
1492 lsa,
1493 )
1494 result = True
1495 else:
1496 errormsg = (
1497 "[DUT: {}] OSPF LSDB area {}: expected"
1498 " ASBR Summary LSA is {}".format(router, ospf_area, lsa)
1499 )
1500 return errormsg
4256a209 1501 if ospf_external_lsa:
701a0192 1502 for ospf_ext_lsa, ext_lsa_data in ospf_external_lsa.items():
1503 if ospf_ext_lsa in show_ospf_json["AS External Link States"]:
1504 logger.info(
1505 "[DUT: %s] OSPF LSDB:External LSA %s", router, ospf_ext_lsa
1506 )
1507 result = True
1508 else:
1509 errormsg = (
1510 "[DUT: {}] OSPF LSDB : expected"
1511 " External LSA is {}".format(router, ospf_ext_lsa)
1512 )
1513 return errormsg
4256a209 1514
1515 logger.debug("Exiting API: verify_ospf_database()")
1516 return result
1517
1518
ed776e38 1519@retry(retry_timeout=20)
8a86be27 1520def verify_ospf_summary(tgen, topo, dut, input_dict, ospf=None, expected=True):
4256a209 1521 """
1522 This API is to verify ospf routes by running
1523 show ip ospf interface command.
1524
1525 Parameters
1526 ----------
1527 * `tgen` : Topogen object
1528 * `topo` : topology descriptions
1529 * `dut`: device under test
1530 * `input_dict` : Input dict data, required when configuring from testcase
1531
1532 Usage
1533 -----
1534 input_dict = {
1535 "11.0.0.0/8": {
1536 "Summary address": "11.0.0.0/8",
1537 "Metric-type": "E2",
1538 "Metric": 20,
1539 "Tag": 0,
1540 "External route count": 5
1541 }
1542 }
1543 result = verify_ospf_summary(tgen, topo, dut, input_dict)
1544
1545 Returns
1546 -------
1547 True or False (Error Message)
1548 """
1549
8a86be27 1550 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
4256a209 1551 result = False
1552 router = dut
1553
1554 logger.info("Verifying OSPF summary on router %s:", router)
1555
4256a209 1556 rnode = tgen.routers()[dut]
8a86be27
MR
1557
1558 if ospf:
a53c08bc
CH
1559 if "ospf6" not in topo["routers"][dut]:
1560 errormsg = "[DUT: {}] OSPF6 is not configured on the router.".format(router)
8a86be27
MR
1561 return errormsg
1562
a53c08bc
CH
1563 show_ospf_json = run_frr_cmd(
1564 rnode, "show ipv6 ospf summary detail json", isjson=True
1565 )
8a86be27 1566 else:
a53c08bc
CH
1567 if "ospf" not in topo["routers"][dut]:
1568 errormsg = "[DUT: {}] OSPF is not configured on the router.".format(router)
8a86be27
MR
1569 return errormsg
1570
a53c08bc
CH
1571 show_ospf_json = run_frr_cmd(
1572 rnode, "show ip ospf summary detail json", isjson=True
1573 )
4256a209 1574
1575 # Verifying output dictionary show_ospf_json is empty or not
1576 if not bool(show_ospf_json):
1577 errormsg = "OSPF is not running"
1578 return errormsg
1579
1580 # To find neighbor ip type
1581 ospf_summary_data = input_dict
8a86be27
MR
1582
1583 if ospf:
a53c08bc 1584 show_ospf_json = show_ospf_json["default"]
8a86be27 1585
4256a209 1586 for ospf_summ, summ_data in ospf_summary_data.items():
1587 if ospf_summ not in show_ospf_json:
1588 continue
a53c08bc 1589 summary = ospf_summary_data[ospf_summ]["Summary address"]
8a86be27 1590
4256a209 1591 if summary in show_ospf_json:
1592 for summ in summ_data:
1593 if summ_data[summ] == show_ospf_json[summary][summ]:
a53c08bc
CH
1594 logger.info(
1595 "[DUT: %s] OSPF summary %s:%s is %s",
1596 router,
1597 summary,
1598 summ,
1599 summ_data[summ],
1600 )
4256a209 1601 result = True
1602 else:
a53c08bc
CH
1603 errormsg = (
1604 "[DUT: {}] OSPF summary {} : {} is {}, "
1605 "Expected is {}".format(
1606 router,
1607 summary,
1608 summ,
1609 show_ospf_json[summary][summ],
1610 summ_data[summ],
1611 )
1612 )
4256a209 1613 return errormsg
1614
8a86be27 1615 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
4256a209 1616 return result
2448d002 1617
1618
ed776e38 1619@retry(retry_timeout=30)
a53c08bc
CH
1620def verify_ospf6_rib(
1621 tgen, dut, input_dict, next_hop=None, tag=None, metric=None, fib=None
1622):
2448d002 1623 """
1624 This API is to verify ospf routes by running
1625 show ip ospf route command.
1626
1627 Parameters
1628 ----------
1629 * `tgen` : Topogen object
1630 * `dut`: device under test
1631 * `input_dict` : Input dict data, required when configuring from testcase
1632 * `next_hop` : next to be verified
1633 * `tag` : tag to be verified
1634 * `metric` : metric to be verified
1635 * `fib` : True if the route is installed in FIB.
1636
1637 Usage
1638 -----
1639 input_dict = {
1640 "r1": {
1641 "static_routes": [
1642 {
1643 "network": ip_net,
1644 "no_of_ip": 1,
1645 "routeType": "N"
1646 }
1647 ]
1648 }
1649 }
1650
1651 result = verify_ospf6_rib(tgen, dut, input_dict,next_hop=nh)
1652
1653 Returns
1654 -------
1655 True or False (Error Message)
1656 """
1657
1658 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
1659 result = False
1660 router_list = tgen.routers()
1661 additional_nexthops_in_required_nhs = []
1662 found_hops = []
1663 for routerInput in input_dict.keys():
c8e5983d 1664 for router, rnode in router_list.items():
2448d002 1665 if router != dut:
1666 continue
1667
1668 logger.info("Checking router %s RIB:", router)
1669
1670 # Verifying RIB routes
d1b5fa5b 1671 command = "show ipv6 ospf route detail"
2448d002 1672
1673 found_routes = []
1674 missing_routes = []
1675
db56171c 1676 if (
1677 "static_routes" in input_dict[routerInput]
1678 or "prefix" in input_dict[routerInput]
1679 ):
2448d002 1680 if "prefix" in input_dict[routerInput]:
1681 static_routes = input_dict[routerInput]["prefix"]
1682 else:
1683 static_routes = input_dict[routerInput]["static_routes"]
1684
2448d002 1685 for static_route in static_routes:
1686 cmd = "{}".format(command)
1687
1688 cmd = "{} json".format(cmd)
1689
db56171c 1690 ospf_rib_json = run_frr_cmd(rnode, cmd, isjson=True)
2448d002 1691
1692 # Fix for PR 2644182
1693 try:
db56171c 1694 ospf_rib_json = ospf_rib_json["routes"]
2448d002 1695 except KeyError:
1696 pass
1697
1698 # Verifying output dictionary ospf_rib_json is not empty
1699 if bool(ospf_rib_json) is False:
db56171c 1700 errormsg = (
1701 "[DUT: {}] No routes found in OSPF6 route "
2448d002 1702 "table".format(router)
db56171c 1703 )
2448d002 1704 return errormsg
1705
1706 network = static_route["network"]
1707 no_of_ip = static_route.setdefault("no_of_ip", 1)
1708 _tag = static_route.setdefault("tag", None)
1709 _rtype = static_route.setdefault("routeType", None)
1710
2448d002 1711 # Generating IPs for verification
1712 ip_list = generate_ips(network, no_of_ip)
d1b5fa5b 1713 if len(ip_list) == 1:
1714 ip_list = [network]
2448d002 1715 st_found = False
1716 nh_found = False
1717 for st_rt in ip_list:
1718 st_rt = str(ipaddress.ip_network(frr_unicode(st_rt)))
1719
1720 _addr_type = validate_ip_address(st_rt)
db56171c 1721 if _addr_type != "ipv6":
2448d002 1722 continue
1723
1724 if st_rt in ospf_rib_json:
1725
1726 st_found = True
1727 found_routes.append(st_rt)
1728
1729 if fib and next_hop:
1730 if type(next_hop) is not list:
1731 next_hop = [next_hop]
1732
1733 for mnh in range(0, len(ospf_rib_json[st_rt])):
db56171c 1734 if (
1735 "fib"
1736 in ospf_rib_json[st_rt][mnh]["nextHops"][0]
1737 ):
1738 found_hops.append(
1739 [
1740 rib_r["ip"]
1741 for rib_r in ospf_rib_json[st_rt][mnh][
1742 "nextHops"
1743 ]
1744 ]
1745 )
2448d002 1746
1747 if found_hops[0]:
db56171c 1748 missing_list_of_nexthops = set(
1749 found_hops[0]
1750 ).difference(next_hop)
1751 additional_nexthops_in_required_nhs = set(
1752 next_hop
1753 ).difference(found_hops[0])
2448d002 1754
1755 if additional_nexthops_in_required_nhs:
1756 logger.info(
1757 "Nexthop "
1758 "%s is not active for route %s in "
1759 "RIB of router %s\n",
1760 additional_nexthops_in_required_nhs,
db56171c 1761 st_rt,
1762 dut,
1763 )
2448d002 1764 errormsg = (
1765 "Nexthop {} is not active"
1766 " for route {} in RIB of router"
1767 " {}\n".format(
db56171c 1768 additional_nexthops_in_required_nhs,
1769 st_rt,
1770 dut,
1771 )
1772 )
2448d002 1773 return errormsg
1774 else:
1775 nh_found = True
1776
1777 elif next_hop and fib is None:
1778 if type(next_hop) is not list:
1779 next_hop = [next_hop]
db56171c 1780 found_hops = [
1781 rib_r["nextHop"]
1782 for rib_r in ospf_rib_json[st_rt]["nextHops"]
1783 ]
2448d002 1784
1785 if found_hops:
db56171c 1786 missing_list_of_nexthops = set(
1787 found_hops
1788 ).difference(next_hop)
1789 additional_nexthops_in_required_nhs = set(
1790 next_hop
1791 ).difference(found_hops)
2448d002 1792 if additional_nexthops_in_required_nhs:
1793 logger.info(
db56171c 1794 "Missing nexthop %s for route"
1795 " %s in RIB of router %s\n",
2448d002 1796 additional_nexthops_in_required_nhs,
db56171c 1797 st_rt,
1798 dut,
1799 )
1800 errormsg = (
1801 "Nexthop {} is Missing for "
1802 "route {} in RIB of router {}\n".format(
1803 additional_nexthops_in_required_nhs,
1804 st_rt,
1805 dut,
1806 )
1807 )
2448d002 1808 return errormsg
1809 else:
1810 nh_found = True
1811 if _rtype:
db56171c 1812 if "destinationType" not in ospf_rib_json[st_rt]:
1813 errormsg = (
1814 "[DUT: {}]: destinationType missing"
1815 "for route {} in OSPF RIB \n".format(dut, st_rt)
1816 )
2448d002 1817 return errormsg
db56171c 1818 elif _rtype != ospf_rib_json[st_rt]["destinationType"]:
1819 errormsg = (
1820 "[DUT: {}]: destinationType mismatch"
1821 "for route {} in OSPF RIB \n".format(dut, st_rt)
1822 )
2448d002 1823 return errormsg
1824 else:
db56171c 1825 logger.info(
1826 "DUT: {}]: Found destinationType {}"
1827 "for route {}".format(dut, _rtype, st_rt)
1828 )
2448d002 1829 if tag:
db56171c 1830 if "tag" not in ospf_rib_json[st_rt]:
1831 errormsg = (
1832 "[DUT: {}]: tag is not"
1833 " present for"
1834 " route {} in RIB \n".format(dut, st_rt)
1835 )
2448d002 1836 return errormsg
1837
db56171c 1838 if _tag != ospf_rib_json[st_rt]["tag"]:
1839 errormsg = (
1840 "[DUT: {}]: tag value {}"
1841 " is not matched for"
1842 " route {} in RIB \n".format(
1843 dut,
1844 _tag,
1845 st_rt,
1846 )
1847 )
2448d002 1848 return errormsg
1849
1850 if metric is not None:
d1b5fa5b 1851 if "metricCostE2" not in ospf_rib_json[st_rt]:
db56171c 1852 errormsg = (
1853 "[DUT: {}]: metric is"
1854 " not present for"
1855 " route {} in RIB \n".format(dut, st_rt)
1856 )
2448d002 1857 return errormsg
1858
d1b5fa5b 1859 if metric != ospf_rib_json[st_rt]["metricCostE2"]:
db56171c 1860 errormsg = (
1861 "[DUT: {}]: metric value "
1862 "{} is not matched for "
1863 "route {} in RIB \n".format(
1864 dut,
1865 metric,
1866 st_rt,
1867 )
1868 )
2448d002 1869 return errormsg
1870
1871 else:
1872 missing_routes.append(st_rt)
1873
1874 if nh_found:
db56171c 1875 logger.info(
1876 "[DUT: {}]: Found next_hop {} for all OSPF"
1877 " routes in RIB".format(router, next_hop)
1878 )
2448d002 1879
1880 if len(missing_routes) > 0:
db56171c 1881 errormsg = "[DUT: {}]: Missing route in RIB, " "routes: {}".format(
1882 dut, missing_routes
1883 )
2448d002 1884 return errormsg
1885
1886 if found_routes:
db56171c 1887 logger.info(
1888 "[DUT: %s]: Verified routes in RIB, found" " routes are: %s\n",
1889 dut,
1890 found_routes,
1891 )
2448d002 1892 result = True
1893
1894 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
1895 return result
1896
1897
ed776e38 1898@retry(retry_timeout=6)
a53c08bc 1899def verify_ospf6_interface(tgen, topo=None, dut=None, lan=False, input_dict=None):
2448d002 1900 """
1901 This API is to verify ospf routes by running
1902 show ip ospf interface command.
1903
1904 Parameters
1905 ----------
1906 * `tgen` : Topogen object
1907 * `topo` : topology descriptions
1908 * `dut`: device under test
1909 * `lan`: if set to true this interface belongs to LAN.
1910 * `input_dict` : Input dict data, required when configuring from testcase
1911
1912 Usage
1913 -----
1914 input_dict= {
1915 'r0': {
1916 'links':{
1917 's1': {
1918 'ospf6':{
1919 'priority':98,
1920 'timerDeadSecs': 4,
1921 'area': '0.0.0.3',
1922 'mcastMemberOspfDesignatedRouters': True,
1923 'mcastMemberOspfAllRouters': True,
1924 'ospfEnabled': True,
1925
1926 }
1927 }
1928 }
1929 }
1930 }
1931 result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
1932
1933 Returns
1934 -------
1935 True or False (Error Message)
1936 """
1937
0afa6453 1938 logger.debug("Entering lib API: verify_ospf6_interface")
2448d002 1939 result = False
1940
49581587
CH
1941 if topo is None:
1942 topo = tgen.json_topo
1943
1944 for router, rnode in tgen.routers().items():
a53c08bc 1945 if "ospf6" not in topo["routers"][router]:
2448d002 1946 continue
1947
1948 if dut is not None and dut != router:
1949 continue
1950
1951 logger.info("Verifying OSPF interface on router %s:", router)
db56171c 1952 show_ospf_json = run_frr_cmd(
1953 rnode, "show ipv6 ospf interface json", isjson=True
1954 )
2448d002 1955
1956 # Verifying output dictionary show_ospf_json is empty or not
1957 if not bool(show_ospf_json):
1958 errormsg = "OSPF6 is not running"
1959 return errormsg
1960
1961 # To find neighbor ip type
1962 ospf_intf_data = input_dict[router]["links"]
1963 for ospf_intf, intf_data in ospf_intf_data.items():
db56171c 1964 intf = topo["routers"][router]["links"][ospf_intf]["interface"]
1965 if intf in show_ospf_json:
1966 for intf_attribute in intf_data["ospf6"]:
1967 if intf_data["ospf6"][intf_attribute] is not list:
1968 if (
1969 intf_data["ospf6"][intf_attribute]
1970 == show_ospf_json[intf][intf_attribute]
1971 ):
1972 logger.info(
1973 "[DUT: %s] OSPF6 interface %s: %s is %s",
1974 router,
1975 intf,
1976 intf_attribute,
1977 intf_data["ospf6"][intf_attribute],
1978 )
1979 elif intf_data["ospf6"][intf_attribute] is list:
2448d002 1980 for addr_list in len(show_ospf_json[intf][intf_attribute]):
db56171c 1981 if (
1982 show_ospf_json[intf][intf_attribute][addr_list][
1983 "address"
1984 ].split("/")[0]
1985 == intf_data["ospf6"]["internetAddress"][0]["address"]
1986 ):
1987 break
2448d002 1988 else:
db56171c 1989 errormsg = "[DUT: {}] OSPF6 interface {}: {} is {}, \
1990 Expected is {}".format(
1991 router,
1992 intf,
1993 intf_attribute,
1994 intf_data["ospf6"][intf_attribute],
1995 intf_data["ospf6"][intf_attribute],
1996 )
2448d002 1997 return errormsg
1998 else:
db56171c 1999 errormsg = "[DUT: {}] OSPF6 interface {}: {} is {}, \
2000 Expected is {}".format(
2001 router,
2002 intf,
2003 intf_attribute,
2004 intf_data["ospf6"][intf_attribute],
2005 intf_data["ospf6"][intf_attribute],
2006 )
2448d002 2007 return errormsg
2008 result = True
2009 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2010 return result
2011
2012
ed776e38 2013@retry(retry_timeout=20)
2448d002 2014def verify_ospf6_database(tgen, topo, dut, input_dict):
2015 """
2016 This API is to verify ospf lsa's by running
2017 show ip ospf database command.
2018
2019 Parameters
2020 ----------
2021 * `tgen` : Topogen object
2022 * `dut`: device under test
2023 * `input_dict` : Input dict data, required when configuring from testcase
2024 * `topo` : next to be verified
2025
2026 Usage
2027 -----
2028 input_dict = {
2029 "areas": {
2030 "0.0.0.0": {
2031 "routerLinkStates": {
2032 "100.1.1.0-100.1.1.0": {
2033 "LSID": "100.1.1.0",
2034 "Advertised router": "100.1.1.0",
2035 "LSA Age": 130,
2036 "Sequence Number": "80000006",
2037 "Checksum": "a703",
2038 "Router links": 3
2039 }
2040 },
2041 "networkLinkStates": {
2042 "10.0.0.2-100.1.1.1": {
2043 "LSID": "10.0.0.2",
2044 "Advertised router": "100.1.1.1",
2045 "LSA Age": 137,
2046 "Sequence Number": "80000001",
2047 "Checksum": "9583"
2048 }
2049 },
2050 },
2051 }
2052 }
2053 result = verify_ospf_database(tgen, topo, dut, input_dict)
2054
2055 Returns
2056 -------
2057 True or False (Error Message)
2058 """
2059
2060 result = False
2061 router = dut
2062 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2063
db56171c 2064 if "ospf" not in topo["routers"][dut]:
2065 errormsg = "[DUT: {}] OSPF is not configured on the router.".format(dut)
2448d002 2066 return errormsg
2067
2068 rnode = tgen.routers()[dut]
2069
2070 logger.info("Verifying OSPF interface on router %s:", dut)
db56171c 2071 show_ospf_json = run_frr_cmd(rnode, "show ip ospf database json", isjson=True)
2448d002 2072 # Verifying output dictionary show_ospf_json is empty or not
2073 if not bool(show_ospf_json):
2074 errormsg = "OSPF is not running"
2075 return errormsg
2076
2077 # for inter and inter lsa's
2078 ospf_db_data = input_dict.setdefault("areas", None)
db56171c 2079 ospf_external_lsa = input_dict.setdefault("asExternalLinkStates", None)
2448d002 2080
2081 if ospf_db_data:
db56171c 2082 for ospf_area, area_lsa in ospf_db_data.items():
2083 if ospf_area in show_ospf_json["areas"]:
2084 if "routerLinkStates" in area_lsa:
2085 for lsa in area_lsa["routerLinkStates"]:
2086 for rtrlsa in show_ospf_json["areas"][ospf_area][
2087 "routerLinkStates"
2088 ]:
2089 if (
2090 lsa["lsaId"] == rtrlsa["lsaId"]
2091 and lsa["advertisedRouter"]
2092 == rtrlsa["advertisedRouter"]
2093 ):
2094 result = True
2448d002 2095 break
db56171c 2096 if result:
2097 logger.info(
2098 "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
2099 router,
2100 ospf_area,
2101 lsa,
2102 )
2103 break
2104 else:
2105 errormsg = (
2106 "[DUT: {}] OSPF LSDB area {}: expected"
2448d002 2107 " Router LSA is {}".format(router, ospf_area, lsa)
db56171c 2108 )
2109 return errormsg
2448d002 2110
db56171c 2111 if "networkLinkStates" in area_lsa:
2112 for lsa in area_lsa["networkLinkStates"]:
2113 for netlsa in show_ospf_json["areas"][ospf_area][
2114 "networkLinkStates"
2115 ]:
2116 if (
2117 lsa
2118 in show_ospf_json["areas"][ospf_area][
2119 "networkLinkStates"
2120 ]
2121 ):
2122 if (
2123 lsa["lsaId"] == netlsa["lsaId"]
2124 and lsa["advertisedRouter"]
2125 == netlsa["advertisedRouter"]
2126 ):
2127 result = True
2128 break
2129 if result:
2130 logger.info(
2131 "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
2132 router,
2133 ospf_area,
2134 lsa,
2135 )
2136 break
2137 else:
2138 errormsg = (
2139 "[DUT: {}] OSPF LSDB area {}: expected"
2448d002 2140 " Network LSA is {}".format(router, ospf_area, lsa)
db56171c 2141 )
2142 return errormsg
2448d002 2143
db56171c 2144 if "summaryLinkStates" in area_lsa:
2145 for lsa in area_lsa["summaryLinkStates"]:
2146 for t3lsa in show_ospf_json["areas"][ospf_area][
2147 "summaryLinkStates"
2148 ]:
2149 if (
2150 lsa["lsaId"] == t3lsa["lsaId"]
2151 and lsa["advertisedRouter"] == t3lsa["advertisedRouter"]
2152 ):
2153 result = True
2448d002 2154 break
db56171c 2155 if result:
2156 logger.info(
2157 "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
2158 router,
2159 ospf_area,
2160 lsa,
2161 )
2162 break
2163 else:
2164 errormsg = (
2165 "[DUT: {}] OSPF LSDB area {}: expected"
2448d002 2166 " Summary LSA is {}".format(router, ospf_area, lsa)
db56171c 2167 )
2168 return errormsg
2448d002 2169
db56171c 2170 if "nssaExternalLinkStates" in area_lsa:
2171 for lsa in area_lsa["nssaExternalLinkStates"]:
2172 for t7lsa in show_ospf_json["areas"][ospf_area][
2173 "nssaExternalLinkStates"
2174 ]:
2175 if (
2176 lsa["lsaId"] == t7lsa["lsaId"]
2177 and lsa["advertisedRouter"] == t7lsa["advertisedRouter"]
2178 ):
2179 result = True
2448d002 2180 break
db56171c 2181 if result:
2182 logger.info(
2183 "[DUT: %s] OSPF LSDB area %s:Type7 " "LSA %s",
2184 router,
2185 ospf_area,
2186 lsa,
2187 )
2188 break
2189 else:
2190 errormsg = (
2191 "[DUT: {}] OSPF LSDB area {}: expected"
2448d002 2192 " Type7 LSA is {}".format(router, ospf_area, lsa)
db56171c 2193 )
2194 return errormsg
2448d002 2195
db56171c 2196 if "asbrSummaryLinkStates" in area_lsa:
2197 for lsa in area_lsa["asbrSummaryLinkStates"]:
2198 for t4lsa in show_ospf_json["areas"][ospf_area][
2199 "asbrSummaryLinkStates"
2200 ]:
2201 if (
2202 lsa["lsaId"] == t4lsa["lsaId"]
2203 and lsa["advertisedRouter"] == t4lsa["advertisedRouter"]
2204 ):
2448d002 2205 result = True
db56171c 2206 break
2207 if result:
2208 logger.info(
2209 "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
2210 router,
2211 ospf_area,
2212 lsa,
2213 )
2214 result = True
2215 else:
2216 errormsg = (
2217 "[DUT: {}] OSPF LSDB area {}: expected"
2218 " ASBR Summary LSA is {}".format(router, ospf_area, lsa)
2219 )
2220 return errormsg
2448d002 2221
db56171c 2222 if "linkLocalOpaqueLsa" in area_lsa:
2223 for lsa in area_lsa["linkLocalOpaqueLsa"]:
2224 try:
2225 for lnklsa in show_ospf_json["areas"][ospf_area][
2226 "linkLocalOpaqueLsa"
2227 ]:
2228 if (
2229 lsa["lsaId"] in lnklsa["lsaId"]
2230 and "linkLocalOpaqueLsa"
2231 in show_ospf_json["areas"][ospf_area]
2232 ):
2233 logger.info(
2234 (
2235 "[DUT: FRR] OSPF LSDB area %s:Opaque-LSA"
2236 "%s",
2237 ospf_area,
2238 lsa,
2239 )
2240 )
2241 result = True
2242 else:
2243 errormsg = (
2244 "[DUT: FRR] OSPF LSDB area: {} "
2245 "expected Opaque-LSA is {}, Found is {}".format(
2246 ospf_area, lsa, show_ospf_json
2247 )
2248 )
2249 raise ValueError(errormsg)
2250 return errormsg
2251 except KeyError:
2252 errormsg = "[DUT: FRR] linkLocalOpaqueLsa Not " "present"
2253 return errormsg
2448d002 2254
2255 if ospf_external_lsa:
db56171c 2256 for lsa in ospf_external_lsa:
2257 try:
2258 for t5lsa in show_ospf_json["asExternalLinkStates"]:
2259 if (
2260 lsa["lsaId"] == t5lsa["lsaId"]
2261 and lsa["advertisedRouter"] == t5lsa["advertisedRouter"]
2262 ):
2263 result = True
2264 break
2265 except KeyError:
2266 result = False
2267 if result:
2268 logger.info("[DUT: %s] OSPF LSDB:External LSA %s", router, lsa)
2269 result = True
2270 else:
2271 errormsg = (
2272 "[DUT: {}] OSPF LSDB : expected"
2273 " External LSA is {}".format(router, lsa)
2274 )
2275 return errormsg
2448d002 2276
2277 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2278 return result
2279
2280
a53c08bc
CH
2281def config_ospf6_interface(
2282 tgen, topo=None, input_dict=None, build=False, load_config=True
2283):
2448d002 2284 """
2285 API to configure ospf on router.
2286
2287 Parameters
2288 ----------
2289 * `tgen` : Topogen object
2290 * `topo` : json file data
2291 * `input_dict` : Input dict data, required when configuring from testcase
2292 * `build` : Only for initial setup phase this is set as True.
2293 * `load_config` : Loading the config to router this is set as True.
2294
2295 Usage
2296 -----
2297 r1_ospf_auth = {
2298 "r1": {
2299 "links": {
2300 "r2": {
2301 "ospf": {
2302 "authentication": 'message-digest',
2303 "authentication-key": "ospf",
2304 "message-digest-key": "10"
2305 }
2306 }
2307 }
2308 }
2309 }
2310 result = config_ospf6_interface(tgen, topo, r1_ospf_auth)
2311
2312 Returns
2313 -------
2314 True or False
2315 """
0afa6453 2316
2448d002 2317 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2318 result = False
49581587
CH
2319 if topo is None:
2320 topo = tgen.json_topo
2321
2448d002 2322 if not input_dict:
2323 input_dict = deepcopy(topo)
2324 else:
2325 input_dict = deepcopy(input_dict)
4f99894d
CH
2326
2327 config_data_dict = {}
2328
2448d002 2329 for router in input_dict.keys():
2330 config_data = []
a53c08bc
CH
2331 for lnk in input_dict[router]["links"].keys():
2332 if "ospf6" not in input_dict[router]["links"][lnk]:
2333 logger.debug(
2334 "Router %s: ospf6 config is not present in"
2335 "input_dict, passed input_dict %s",
2336 router,
2337 str(input_dict),
2338 )
2448d002 2339 continue
db56171c 2340 ospf_data = input_dict[router]["links"][lnk]["ospf6"]
2448d002 2341 data_ospf_area = ospf_data.setdefault("area", None)
db56171c 2342 data_ospf_auth = ospf_data.setdefault("hash-algo", None)
0afa6453 2343 data_ospf_keychain = ospf_data.setdefault("keychain", None)
2448d002 2344 data_ospf_dr_priority = ospf_data.setdefault("priority", None)
2345 data_ospf_cost = ospf_data.setdefault("cost", None)
2346 data_ospf_mtu = ospf_data.setdefault("mtu_ignore", None)
2347
2348 try:
db56171c 2349 intf = topo["routers"][router]["links"][lnk]["interface"]
2448d002 2350 except KeyError:
db56171c 2351 intf = topo["switches"][router]["links"][lnk]["interface"]
2448d002 2352
2353 # interface
2354 cmd = "interface {}".format(intf)
2355
2356 config_data.append(cmd)
2357 # interface area config
2358 if data_ospf_area:
2359 cmd = "ipv6 ospf area {}".format(data_ospf_area)
2360 config_data.append(cmd)
2361
db56171c 2362 # interface ospf auth
2363 if data_ospf_auth:
2364 cmd = "ipv6 ospf6 authentication"
2365
2366 if "del_action" in ospf_data:
2367 cmd = "no {}".format(cmd)
2368
2369 if "hash-algo" in ospf_data:
2370 cmd = "{} key-id {} hash-algo {} key {}".format(
2371 cmd,
2372 ospf_data["key-id"],
2373 ospf_data["hash-algo"],
2374 ospf_data["key"],
2375 )
0afa6453
AR
2376 config_data.append(cmd)
2377
2378 # interface ospf auth with keychain
2379 if data_ospf_keychain:
2380 cmd = "ipv6 ospf6 authentication"
2381
2382 if "del_action" in ospf_data:
2383 cmd = "no {}".format(cmd)
2384
2385 if "keychain" in ospf_data:
2386 cmd = "{} keychain {}".format(cmd, ospf_data["keychain"])
2387 config_data.append(cmd)
db56171c 2388
2448d002 2389 # interface ospf dr priority
2390 if data_ospf_dr_priority:
db56171c 2391 cmd = "ipv6 ospf priority {}".format(ospf_data["priority"])
2392 if "del_action" in ospf_data:
2448d002 2393 cmd = "no {}".format(cmd)
2394 config_data.append(cmd)
2395
2396 # interface ospf cost
2397 if data_ospf_cost:
db56171c 2398 cmd = "ipv6 ospf cost {}".format(ospf_data["cost"])
2399 if "del_action" in ospf_data:
2448d002 2400 cmd = "no {}".format(cmd)
2401 config_data.append(cmd)
2402
2403 # interface ospf mtu
2404 if data_ospf_mtu:
2405 cmd = "ipv6 ospf mtu-ignore"
db56171c 2406 if "del_action" in ospf_data:
2448d002 2407 cmd = "no {}".format(cmd)
2408 config_data.append(cmd)
2409
2410 if build:
2411 return config_data
4f99894d
CH
2412
2413 if config_data:
2414 config_data_dict[router] = config_data
2415
2416 result = create_common_configurations(
2417 tgen, config_data_dict, "interface_config", build=build
2418 )
2419
2448d002 2420 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2421 return result
cc90defc 2422
a53c08bc 2423
cc90defc 2424@retry(retry_timeout=20)
2425def verify_ospf_gr_helper(tgen, topo, dut, input_dict=None):
2426 """
2427 This API is used to vreify gr helper using command
2428 show ip ospf graceful-restart helper
2429
2430 Parameters
2431 ----------
2432 * `tgen` : Topogen object
2433 * `topo` : topology descriptions
2434 * 'dut' : router
2435 * 'input_dict' - values to be verified
2436
2437 Usage:
2438 -------
2439 input_dict = {
2440 "helperSupport":"Disabled",
2441 "strictLsaCheck":"Enabled",
2442 "restartSupoort":"Planned and Unplanned Restarts",
2443 "supportedGracePeriod":1800
2444 }
2445 result = verify_ospf_gr_helper(tgen, topo, dut, input_dict)
2446
2447 """
2448 logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
2449 result = False
2450
a53c08bc
CH
2451 if "ospf" not in topo["routers"][dut]:
2452 errormsg = "[DUT: {}] OSPF is not configured on the router.".format(dut)
cc90defc 2453 return errormsg
2454
2455 rnode = tgen.routers()[dut]
2456 logger.info("Verifying OSPF GR details on router %s:", dut)
a53c08bc
CH
2457 show_ospf_json = run_frr_cmd(
2458 rnode, "show ip ospf graceful-restart helper json", isjson=True
2459 )
cc90defc 2460
2461 # Verifying output dictionary show_ospf_json is empty or not
2462 if not bool(show_ospf_json):
2463 errormsg = "OSPF is not running"
a53c08bc 2464 raise ValueError(errormsg)
cc90defc 2465 return errormsg
2466
a53c08bc 2467 for ospf_gr, gr_data in input_dict.items():
cc90defc 2468 try:
2469 if input_dict[ospf_gr] == show_ospf_json[ospf_gr]:
a53c08bc
CH
2470 logger.info(
2471 "[DUT: FRR] OSPF GR Helper: %s is %s",
2472 ospf_gr,
2473 show_ospf_json[ospf_gr],
2474 )
cc90defc 2475 result = True
2476 else:
a53c08bc
CH
2477 errormsg = (
2478 "[DUT: FRR] OSPF GR Helper: {} expected is {}, Found "
2479 "is {}".format(
2480 ospf_gr, input_dict[ospf_gr], show_ospf_json[ospf_gr]
2481 )
2482 )
2483 raise ValueError(errormsg)
cc90defc 2484 return errormsg
2485
2486 except KeyError:
a53c08bc 2487 errormsg = "[DUT: FRR] OSPF GR Helper: {}".format(ospf_gr)
cc90defc 2488 return errormsg
2489
2490 logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
2491 return result