1 # SPDX-License-Identifier: ISC
3 # Copyright (c) 2020 by VMware, Inc. ("VMware")
4 # Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
5 # ("NetDEF") in this file.
10 from copy
import deepcopy
11 from time
import sleep
13 # Import common_config to use commomnly used APIs
14 from lib
.common_config
import (
15 create_common_configurations
,
22 from lib
.topolog
import logger
23 from lib
.topotest
import frr_unicode
25 ################################
27 ################################
30 def create_router_ospf(tgen
, topo
=None, input_dict
=None, build
=False, load_config
=True):
32 API to configure ospf on router.
36 * `tgen` : Topogen object
37 * `topo` : json file data
38 * `input_dict` : Input dict data, required when configuring from testcase
39 * `build` : Only for initial setup phase this is set as True.
40 * `load_config` : Loading the config to router this is set as True.
47 "router_id": "22.22.22.22",
48 "area": [{ "id": "0.0.0.0", "type": "nssa"}]
52 result = create_router_ospf(tgen, topo, input_dict)
58 logger
.debug("Entering lib API: create_router_ospf()")
65 input_dict
= deepcopy(topo
)
67 topo
= topo
["routers"]
68 input_dict
= deepcopy(input_dict
)
70 for ospf
in ["ospf", "ospf6"]:
73 for router
in input_dict
.keys():
74 if ospf
not in input_dict
[router
]:
75 logger
.debug("Router %s: %s not present in input_dict", router
, ospf
)
78 config_data
= __create_ospf_global(
79 tgen
, input_dict
, router
, build
, load_config
, ospf
82 if router
not in config_data_dict
:
83 config_data_dict
[router
] = config_data
85 config_data_dict
[router
].extend(config_data
)
87 result
= create_common_configurations(
88 tgen
, config_data_dict
, ospf
, build
, load_config
90 except InvalidCLIError
:
91 logger
.error("create_router_ospf (ipv4)", exc_info
=True)
94 logger
.debug("Exiting lib API: create_router_ospf()")
98 def __create_ospf_global(tgen
, input_dict
, router
, build
, load_config
, ospf
):
100 Helper API to create ospf global configuration.
104 * `tgen` : Topogen object
105 * `input_dict` : Input dict data, required when configuring from testcase
106 * `router` : router to be configured.
107 * `build` : Only for initial setup phase this is set as True.
108 * `load_config` : Loading the config to router this is set as True.
109 * `ospf` : either 'ospf' or 'ospf6'
118 "ipv6": "2013:13::1/64",
122 "network": "point-to-point"
127 "router_id": "1.1.1.1",
139 list of configuration commands
144 if ospf
not in input_dict
[router
]:
147 logger
.debug("Entering lib API: __create_ospf_global()")
149 ospf_data
= input_dict
[router
][ospf
]
150 del_ospf_action
= ospf_data
.setdefault("delete", False)
152 config_data
= ["no router {}".format(ospf
)]
155 cmd
= "router {}".format(ospf
)
157 config_data
.append(cmd
)
160 router_id
= ospf_data
.setdefault("router_id", None)
161 del_router_id
= ospf_data
.setdefault("del_router_id", False)
163 config_data
.append("no {} router-id".format(ospf
))
165 config_data
.append("{} router-id {}".format(ospf
, router_id
))
167 # log-adjacency-changes
168 log_adj_changes
= ospf_data
.setdefault("log_adj_changes", None)
169 del_log_adj_changes
= ospf_data
.setdefault("del_log_adj_changes", False)
170 if del_log_adj_changes
:
171 config_data
.append("no log-adjacency-changes detail")
173 config_data
.append("log-adjacency-changes {}".format(log_adj_changes
))
176 aggr_timer
= ospf_data
.setdefault("aggr_timer", None)
177 del_aggr_timer
= ospf_data
.setdefault("del_aggr_timer", False)
179 config_data
.append("no aggregation timer")
181 config_data
.append("aggregation timer {}".format(aggr_timer
))
183 # maximum path information
184 ecmp_data
= ospf_data
.setdefault("maximum-paths", {})
186 cmd
= "maximum-paths {}".format(ecmp_data
)
187 del_action
= ospf_data
.setdefault("del_max_path", False)
189 cmd
= "no maximum-paths"
190 config_data
.append(cmd
)
193 flood_data
= ospf_data
.setdefault("flood-reduction", {})
195 cmd
= "flood-reduction"
196 del_action
= ospf_data
.setdefault("del_flood_reduction", False)
198 cmd
= "no flood-reduction"
199 config_data
.append(cmd
)
201 # LSA refresh timer - A hidden command.
202 refresh_data
= ospf_data
.setdefault("lsa-refresh", {})
204 cmd
= "ospf lsa-refresh {}".format(refresh_data
)
205 del_action
= ospf_data
.setdefault("del_lsa_refresh", False)
207 cmd
= "no ospf lsa-refresh"
208 config_data
.append(cmd
)
210 # redistribute command
211 redistribute_data
= ospf_data
.setdefault("redistribute", {})
212 if redistribute_data
:
213 for redistribute
in redistribute_data
:
214 if "redist_type" not in redistribute
:
216 "Router %s: 'redist_type' not present in " "input_dict", router
219 cmd
= "redistribute {}".format(redistribute
["redist_type"])
220 for red_type
in redistribute_data
:
221 if "route_map" in red_type
:
222 cmd
= cmd
+ " route-map {}".format(red_type
["route_map"])
223 del_action
= redistribute
.setdefault("delete", False)
225 cmd
= "no {}".format(cmd
)
226 config_data
.append(cmd
)
229 area_data
= ospf_data
.setdefault("area", {})
231 for area
in area_data
:
234 "Router %s: 'area id' not present in " "input_dict", router
237 cmd
= "area {}".format(area
["id"])
240 cmd
= cmd
+ " {}".format(area
["type"])
242 if "flood-reduction" in area
:
243 cmd
= cmd
+ " flood-reduction"
245 del_action
= area
.setdefault("delete", False)
247 cmd
= "no {}".format(cmd
)
248 config_data
.append(cmd
)
250 # def route information
251 def_rte_data
= ospf_data
.setdefault("default-information", {})
253 if "originate" not in def_rte_data
:
255 "Router %s: 'originate key' not present in " "input_dict", router
258 cmd
= "default-information originate"
260 if "always" in def_rte_data
:
261 cmd
= cmd
+ " always"
263 if "metric" in def_rte_data
:
264 cmd
= cmd
+ " metric {}".format(def_rte_data
["metric"])
266 if "metric-type" in def_rte_data
:
267 cmd
= cmd
+ " metric-type {}".format(def_rte_data
["metric-type"])
269 if "route-map" in def_rte_data
:
270 cmd
= cmd
+ " route-map {}".format(def_rte_data
["route-map"])
272 del_action
= def_rte_data
.setdefault("delete", False)
274 cmd
= "no {}".format(cmd
)
275 config_data
.append(cmd
)
277 # summary information
278 summary_data
= ospf_data
.setdefault("summary-address", {})
280 for summary
in summary_data
:
281 if "prefix" not in summary
:
283 "Router %s: 'summary-address' not present in " "input_dict",
287 cmd
= "summary {}/{}".format(summary
["prefix"], summary
["mask"])
289 _tag
= summary
.setdefault("tag", None)
291 cmd
= "{} tag {}".format(cmd
, _tag
)
293 _advertise
= summary
.setdefault("advertise", True)
295 cmd
= "{} no-advertise".format(cmd
)
297 del_action
= summary
.setdefault("delete", False)
299 cmd
= "no {}".format(cmd
)
300 config_data
.append(cmd
)
302 # ospf gr information
303 gr_data
= ospf_data
.setdefault("graceful-restart", {})
306 if "opaque" in gr_data
and gr_data
["opaque"]:
307 cmd
= "capability opaque"
308 if gr_data
.setdefault("delete", False):
309 cmd
= "no {}".format(cmd
)
310 config_data
.append(cmd
)
312 if "helper enable" in gr_data
and not gr_data
["helper enable"]:
313 cmd
= "graceful-restart helper enable"
314 if gr_data
.setdefault("delete", False):
315 cmd
= "no {}".format(cmd
)
316 config_data
.append(cmd
)
317 elif "helper enable" in gr_data
and type(gr_data
["helper enable"]) is list:
318 for rtrs
in gr_data
["helper enable"]:
319 cmd
= "graceful-restart helper enable {}".format(rtrs
)
320 if gr_data
.setdefault("delete", False):
321 cmd
= "no {}".format(cmd
)
322 config_data
.append(cmd
)
324 if "helper" in gr_data
:
325 if type(gr_data
["helper"]) is not list:
326 gr_data
["helper"] = list(gr_data
["helper"])
327 for helper_role
in gr_data
["helper"]:
328 cmd
= "graceful-restart helper {}".format(helper_role
)
329 if gr_data
.setdefault("delete", False):
330 cmd
= "no {}".format(cmd
)
331 config_data
.append(cmd
)
333 if "supported-grace-time" in gr_data
:
334 cmd
= "graceful-restart helper supported-grace-time {}".format(
335 gr_data
["supported-grace-time"]
337 if gr_data
.setdefault("delete", False):
338 cmd
= "no {}".format(cmd
)
339 config_data
.append(cmd
)
341 logger
.debug("Exiting lib API: create_ospf_global()")
346 def config_ospf_interface(
347 tgen
, topo
=None, input_dict
=None, build
=False, load_config
=True
350 API to configure ospf on router.
354 * `tgen` : Topogen object
355 * `topo` : json file data
356 * `input_dict` : Input dict data, required when configuring from testcase
357 * `build` : Only for initial setup phase this is set as True.
358 * `load_config` : Loading the config to router this is set as True.
367 "authentication": "message-digest",
368 "authentication-key": "ospf",
369 "message-digest-key": "10"
375 result = config_ospf_interface(tgen, topo, r1_ospf_auth)
381 logger
.debug("Enter lib config_ospf_interface")
385 topo
= tgen
.json_topo
388 input_dict
= deepcopy(topo
)
390 input_dict
= deepcopy(input_dict
)
392 config_data_dict
= {}
394 for router
in input_dict
.keys():
396 for lnk
in input_dict
[router
]["links"].keys():
397 if "ospf" not in input_dict
[router
]["links"][lnk
]:
399 "Router %s: ospf config is not present in" "input_dict", router
402 ospf_data
= input_dict
[router
]["links"][lnk
]["ospf"]
403 data_ospf_area
= ospf_data
.setdefault("area", None)
404 data_ospf_auth
= ospf_data
.setdefault("authentication", None)
405 data_ospf_dr_priority
= ospf_data
.setdefault("priority", None)
406 data_ospf_cost
= ospf_data
.setdefault("cost", None)
407 data_ospf_mtu
= ospf_data
.setdefault("mtu_ignore", None)
410 intf
= topo
["routers"][router
]["links"][lnk
]["interface"]
412 intf
= topo
["switches"][router
]["links"][lnk
]["interface"]
415 cmd
= "interface {}".format(intf
)
417 config_data
.append(cmd
)
418 # interface area config
420 cmd
= "ip ospf area {}".format(data_ospf_area
)
421 config_data
.append(cmd
)
423 # interface ospf auth
425 if data_ospf_auth
== "null":
426 cmd
= "ip ospf authentication null"
427 elif data_ospf_auth
== "message-digest":
428 cmd
= "ip ospf authentication message-digest"
430 cmd
= "ip ospf authentication"
432 if "del_action" in ospf_data
:
433 cmd
= "no {}".format(cmd
)
434 config_data
.append(cmd
)
436 if "message-digest-key" in ospf_data
:
437 cmd
= "ip ospf message-digest-key {} md5 {}".format(
438 ospf_data
["message-digest-key"], ospf_data
["authentication-key"]
440 if "del_action" in ospf_data
:
441 cmd
= "no {}".format(cmd
)
442 config_data
.append(cmd
)
445 "authentication-key" in ospf_data
446 and "message-digest-key" not in ospf_data
448 cmd
= "ip ospf authentication-key {}".format(
449 ospf_data
["authentication-key"]
451 if "del_action" in ospf_data
:
452 cmd
= "no {}".format(cmd
)
453 config_data
.append(cmd
)
455 # interface ospf dr priority
456 if data_ospf_dr_priority
:
457 cmd
= "ip ospf priority {}".format(ospf_data
["priority"])
458 if "del_action" in ospf_data
:
459 cmd
= "no {}".format(cmd
)
460 config_data
.append(cmd
)
462 # interface ospf cost
464 cmd
= "ip ospf cost {}".format(ospf_data
["cost"])
465 if "del_action" in ospf_data
:
466 cmd
= "no {}".format(cmd
)
467 config_data
.append(cmd
)
471 cmd
= "ip ospf mtu-ignore"
472 if "del_action" in ospf_data
:
473 cmd
= "no {}".format(cmd
)
474 config_data
.append(cmd
)
480 config_data_dict
[router
] = config_data
482 result
= create_common_configurations(
483 tgen
, config_data_dict
, "interface_config", build
=build
486 logger
.debug("Exiting lib API: config_ospf_interface()")
490 def clear_ospf(tgen
, router
, ospf
=None):
492 This API is to clear ospf neighborship by running
493 clear ip ospf interface * command,
497 * `tgen`: topogen object
498 * `router`: device under test
502 clear_ospf(tgen, "r1")
505 logger
.debug("Entering lib API: clear_ospf()")
506 if router
not in tgen
.routers():
509 rnode
= tgen
.routers()[router
]
516 cmd
= "clear {} ospf interface".format(version
)
517 logger
.info("Clearing ospf process on router %s.. using command '%s'", router
, cmd
)
518 run_frr_cmd(rnode
, cmd
)
520 logger
.debug("Exiting lib API: clear_ospf()")
523 def redistribute_ospf(tgen
, topo
, dut
, route_type
, **kwargs
):
525 Redstribution of routes inside ospf.
529 * `tgen`: Topogen object
530 * `topo` : json file data
531 * `dut`: device under test
532 * `route_type`: "static" or "connected" or ....
533 * `kwargs`: pass extra information (see below)
537 redistribute_ospf(tgen, topo, "r0", "static", delete=True)
538 redistribute_ospf(tgen, topo, "r0", "static", route_map="rmap_ipv4")
541 ospf_red
= {dut
: {"ospf": {"redistribute": [{"redist_type": route_type
}]}}}
542 for k
, v
in kwargs
.items():
543 ospf_red
[dut
]["ospf"]["redistribute"][0][k
] = v
545 result
= create_router_ospf(tgen
, topo
, ospf_red
)
546 assert result
is True, "Testcase : Failed \n Error: {}".format(result
)
549 ################################
551 ################################
552 @retry(retry_timeout
=80)
553 def verify_ospf_neighbor(
554 tgen
, topo
=None, dut
=None, input_dict
=None, lan
=False, expected
=True
557 This API is to verify ospf neighborship by running
558 show ip ospf neighbour command,
562 * `tgen` : Topogen object
563 * `topo` : json file data
564 * `dut`: device under test
565 * `input_dict` : Input dict data, required when configuring from testcase
566 * `lan` : verify neighbors in lan topology
567 * `expected` : expected results from API, by-default True
571 1. To check FULL neighbors.
572 verify_ospf_neighbor(tgen, topo, dut=dut)
574 2. To check neighbors with their roles.
595 result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
599 True or False (Error Message)
601 logger
.debug("Entering lib API: verify_ospf_neighbor()")
604 topo
= tgen
.json_topo
607 for router
, rnode
in tgen
.routers().items():
608 if "ospf" not in topo
["routers"][router
]:
611 if dut
is not None and dut
!= router
:
614 logger
.info("Verifying OSPF neighborship on router %s:", router
)
615 show_ospf_json
= run_frr_cmd(
616 rnode
, "show ip ospf neighbor all json", isjson
=True
619 # Verifying output dictionary show_ospf_json is empty or not
620 if not bool(show_ospf_json
):
621 errormsg
= "OSPF is not running"
624 ospf_data_list
= input_dict
[router
]["ospf"]
625 ospf_nbr_list
= ospf_data_list
["neighbors"]
627 for ospf_nbr
, nbr_data
in ospf_nbr_list
.items():
628 data_ip
= topo
["routers"][ospf_nbr
]["links"]
629 data_rid
= topo
["routers"][ospf_nbr
]["ospf"]["router_id"]
630 if ospf_nbr
in data_ip
:
631 nbr_details
= nbr_data
[ospf_nbr
]
633 for switch
in topo
["switches"]:
634 if "ospf" in topo
["switches"][switch
]["links"][router
]:
635 neighbor_ip
= data_ip
[switch
]["ipv4"].split("/")[0]
639 neighbor_ip
= data_ip
[router
]["ipv4"].split("/")[0]
642 neighbor_ip
= neighbor_ip
.lower()
645 nh_state
= show_ospf_json
[nbr_rid
][0]["nbrState"].split("/")[0]
646 intf_state
= show_ospf_json
[nbr_rid
][0]["nbrState"].split("/")[1]
648 errormsg
= "[DUT: {}] OSPF peer {} missing".format(router
, nbr_rid
)
651 nbr_state
= nbr_data
.setdefault("nbrState", None)
652 nbr_role
= nbr_data
.setdefault("role", None)
655 if nbr_state
== nh_state
:
657 "[DUT: {}] OSPF Nbr is {}:{} State {}".format(
658 router
, ospf_nbr
, nbr_rid
, nh_state
664 "[DUT: {}] OSPF is not Converged, neighbor"
665 " state is {}".format(router
, nh_state
)
669 if nbr_role
== intf_state
:
671 "[DUT: {}] OSPF Nbr is {}: {} Role {}".format(
672 router
, ospf_nbr
, nbr_rid
, nbr_role
677 "[DUT: {}] OSPF is not Converged with rid"
678 "{}, role is {}".format(router
, nbr_rid
, intf_state
)
683 for router
, rnode
in tgen
.routers().items():
684 if "ospf" not in topo
["routers"][router
]:
687 if dut
is not None and dut
!= router
:
690 logger
.info("Verifying OSPF neighborship on router %s:", router
)
691 show_ospf_json
= run_frr_cmd(
692 rnode
, "show ip ospf neighbor all json", isjson
=True
694 # Verifying output dictionary show_ospf_json is empty or not
695 if not bool(show_ospf_json
):
696 errormsg
= "OSPF is not running"
699 ospf_data_list
= topo
["routers"][router
]["ospf"]
700 ospf_neighbors
= ospf_data_list
["neighbors"]
702 total_peer
= len(ospf_neighbors
.keys())
704 ospf_nbr_list
= ospf_data_list
["neighbors"]
706 for ospf_nbr
, nbr_data
in ospf_nbr_list
.items():
708 data_ip
= topo
["routers"][nbr_data
["nbr"]]["links"]
709 data_rid
= topo
["routers"][nbr_data
["nbr"]]["ospf"]["router_id"]
711 data_ip
= topo
["routers"][ospf_nbr
]["links"]
712 data_rid
= topo
["routers"][ospf_nbr
]["ospf"]["router_id"]
713 if ospf_nbr
in data_ip
:
714 nbr_details
= nbr_data
[ospf_nbr
]
716 for switch
in topo
["switches"]:
717 if "ospf" in topo
["switches"][switch
]["links"][router
]:
718 neighbor_ip
= data_ip
[switch
]["ipv4"].split("/")[0]
722 neighbor_ip
= data_ip
[router
]["ipv4"].split("/")[0]
725 neighbor_ip
= neighbor_ip
.lower()
729 nh_state
= show_ospf_json
[nbr_rid
][0]["nbrState"].split("/")[0]
731 errormsg
= "[DUT: {}] OSPF peer {} missing,from " "{} ".format(
732 router
, nbr_rid
, ospf_nbr
736 if nh_state
== "Full":
739 if no_of_peer
== total_peer
:
740 logger
.info("[DUT: {}] OSPF is Converged".format(router
))
743 errormsg
= "[DUT: {}] OSPF is not Converged".format(router
)
746 logger
.debug("Exiting API: verify_ospf_neighbor()")
750 @retry(retry_timeout
=50)
751 def verify_ospf6_neighbor(tgen
, topo
=None, dut
=None, input_dict
=None, lan
=False):
753 This API is to verify ospf neighborship by running
754 show ipv6 ospf neighbour command,
758 * `tgen` : Topogen object
759 * `topo` : json file data
760 * `dut`: device under test
761 * `input_dict` : Input dict data, required when configuring from testcase
762 * `lan` : verify neighbors in lan topology
766 1. To check FULL neighbors.
767 verify_ospf_neighbor(tgen, topo, dut=dut)
769 2. To check neighbors with their roles.
790 result = verify_ospf6_neighbor(tgen, topo, dut, input_dict, lan=True)
792 3. To check there are no neighbors.
800 result = verify_ospf6_neighbor(tgen, topo, dut, input_dict)
804 True or False (Error Message)
806 logger
.debug("Entering lib API: {}".format(sys
._getframe
().f_code
.co_name
))
810 topo
= tgen
.json_topo
813 for router
, rnode
in tgen
.routers().items():
814 if "ospf6" not in topo
["routers"][router
]:
817 if dut
is not None and dut
!= router
:
820 logger
.info("Verifying OSPF neighborship on router %s:", router
)
821 show_ospf_json
= run_frr_cmd(
822 rnode
, "show ipv6 ospf neighbor json", isjson
=True
824 # Verifying output dictionary show_ospf_json is empty or not
825 if not bool(show_ospf_json
):
826 errormsg
= "OSPF6 is not running"
829 ospf_data_list
= input_dict
[router
]["ospf6"]
830 ospf_nbr_list
= ospf_data_list
["neighbors"]
832 # Check if looking for no neighbors
833 if ospf_nbr_list
== []:
834 if show_ospf_json
["neighbors"] == []:
835 logger
.info("[DUT: {}] OSPF6 no neighbors found".format(router
))
839 "[DUT: {}] OSPF6 active neighbors found, expected None".format(
845 for ospf_nbr
, nbr_data
in ospf_nbr_list
.items():
848 data_ip
= data_rid
= topo
["routers"][ospf_nbr
]["ospf6"]["router_id"]
850 data_ip
= data_rid
= topo
["routers"][nbr_data
["nbr"]]["ospf6"][
854 if ospf_nbr
in data_ip
:
855 nbr_details
= nbr_data
[ospf_nbr
]
857 for switch
in topo
["switches"]:
858 if "ospf6" in topo
["switches"][switch
]["links"][router
]:
859 neighbor_ip
= data_ip
863 neighbor_ip
= data_ip
[router
]["ipv6"].split("/")[0]
866 neighbor_ip
= neighbor_ip
.lower()
868 get_index_val
= dict(
869 (d
["neighborId"], dict(d
, index
=index
))
870 for (index
, d
) in enumerate(show_ospf_json
["neighbors"])
873 nh_state
= get_index_val
.get(neighbor_ip
)["state"]
874 intf_state
= get_index_val
.get(neighbor_ip
)["ifState"]
876 errormsg
= "[DUT: {}] OSPF peer {} missing,from " "{} ".format(
877 router
, nbr_rid
, ospf_nbr
881 nbr_state
= nbr_data
.setdefault("state", None)
882 nbr_role
= nbr_data
.setdefault("role", None)
885 if nbr_state
== nh_state
:
887 "[DUT: {}] OSPF6 Nbr is {}:{} State {}".format(
888 router
, ospf_nbr
, nbr_rid
, nh_state
894 "[DUT: {}] OSPF6 is not Converged, neighbor"
895 " state is {} , Expected state is {}".format(
896 router
, nh_state
, nbr_state
901 if nbr_role
== intf_state
:
903 "[DUT: {}] OSPF6 Nbr is {}: {} Role {}".format(
904 router
, ospf_nbr
, nbr_rid
, nbr_role
909 "[DUT: {}] OSPF6 is not Converged with rid"
910 "{}, role is {}, Expected role is {}".format(
911 router
, nbr_rid
, intf_state
, nbr_role
918 for router
, rnode
in tgen
.routers().items():
919 if "ospf6" not in topo
["routers"][router
]:
922 if dut
is not None and dut
!= router
:
925 logger
.info("Verifying OSPF6 neighborship on router %s:", router
)
926 show_ospf_json
= run_frr_cmd(
927 rnode
, "show ipv6 ospf neighbor json", isjson
=True
929 # Verifying output dictionary show_ospf_json is empty or not
930 if not bool(show_ospf_json
):
931 errormsg
= "OSPF6 is not running"
934 ospf_data_list
= topo
["routers"][router
]["ospf6"]
935 ospf_neighbors
= ospf_data_list
["neighbors"]
937 total_peer
= len(ospf_neighbors
.keys())
939 ospf_nbr_list
= ospf_data_list
["neighbors"]
941 for ospf_nbr
, nbr_data
in ospf_nbr_list
.items():
943 data_ip
= data_rid
= topo
["routers"][ospf_nbr
]["ospf6"]["router_id"]
945 data_ip
= data_rid
= topo
["routers"][nbr_data
["nbr"]]["ospf6"][
949 if ospf_nbr
in data_ip
:
950 nbr_details
= nbr_data
[ospf_nbr
]
952 for switch
in topo
["switches"]:
953 if "ospf6" in topo
["switches"][switch
]["links"][router
]:
954 neighbor_ip
= data_ip
958 neighbor_ip
= data_ip
961 neighbor_ip
= neighbor_ip
.lower()
963 get_index_val
= dict(
964 (d
["neighborId"], dict(d
, index
=index
))
965 for (index
, d
) in enumerate(show_ospf_json
["neighbors"])
968 nh_state
= get_index_val
.get(neighbor_ip
)["state"]
969 intf_state
= get_index_val
.get(neighbor_ip
)["ifState"]
971 errormsg
= "[DUT: {}] OSPF peer {} missing,from " "{} ".format(
972 router
, nbr_rid
, ospf_nbr
976 if nh_state
== "Full":
979 if no_of_peer
== total_peer
:
980 logger
.info("[DUT: {}] OSPF6 is Converged".format(router
))
983 errormsg
= "[DUT: {}] OSPF6 is not Converged".format(router
)
986 logger
.debug("Exiting lib API: {}".format(sys
._getframe
().f_code
.co_name
))
990 @retry(retry_timeout
=40)
992 tgen
, dut
, input_dict
, next_hop
=None, tag
=None, metric
=None, fib
=None, expected
=True
995 This API is to verify ospf routes by running
996 show ip ospf route command.
1000 * `tgen` : Topogen object
1001 * `dut`: device under test
1002 * `input_dict` : Input dict data, required when configuring from testcase
1003 * `next_hop` : next to be verified
1004 * `tag` : tag to be verified
1005 * `metric` : metric to be verified
1006 * `fib` : True if the route is installed in FIB.
1007 * `expected` : expected results from API, by-default True
1023 result = verify_ospf_rib(tgen, dut, input_dict,next_hop=nh)
1027 True or False (Error Message)
1030 logger
.info("Entering lib API: verify_ospf_rib()")
1032 router_list
= tgen
.routers()
1033 additional_nexthops_in_required_nhs
= []
1035 for routerInput
in input_dict
.keys():
1036 for router
, rnode
in router_list
.items():
1040 logger
.info("Checking router %s RIB:", router
)
1042 # Verifying RIB routes
1043 command
= "show ip ospf route"
1049 "static_routes" in input_dict
[routerInput
]
1050 or "prefix" in input_dict
[routerInput
]
1052 if "prefix" in input_dict
[routerInput
]:
1053 static_routes
= input_dict
[routerInput
]["prefix"]
1055 static_routes
= input_dict
[routerInput
]["static_routes"]
1057 for static_route
in static_routes
:
1058 cmd
= "{}".format(command
)
1060 cmd
= "{} json".format(cmd
)
1062 ospf_rib_json
= run_frr_cmd(rnode
, cmd
, isjson
=True)
1064 # Verifying output dictionary ospf_rib_json is not empty
1065 if bool(ospf_rib_json
) is False:
1067 "[DUT: {}] No routes found in OSPF route "
1068 "table".format(router
)
1072 network
= static_route
["network"]
1073 no_of_ip
= static_route
.setdefault("no_of_ip", 1)
1074 _tag
= static_route
.setdefault("tag", None)
1075 _rtype
= static_route
.setdefault("routeType", None)
1077 # Generating IPs for verification
1078 ip_list
= generate_ips(network
, no_of_ip
)
1082 for st_rt
in ip_list
:
1083 st_rt
= str(ipaddress
.ip_network(frr_unicode(st_rt
)))
1085 _addr_type
= validate_ip_address(st_rt
)
1086 if _addr_type
!= "ipv4":
1089 if st_rt
in ospf_rib_json
:
1091 found_routes
.append(st_rt
)
1093 if fib
and next_hop
:
1094 if type(next_hop
) is not list:
1095 next_hop
= [next_hop
]
1097 for mnh
in range(0, len(ospf_rib_json
[st_rt
])):
1100 in ospf_rib_json
[st_rt
][mnh
]["nexthops"][0]
1105 for rib_r
in ospf_rib_json
[st_rt
][mnh
][
1112 missing_list_of_nexthops
= set(
1114 ).difference(next_hop
)
1115 additional_nexthops_in_required_nhs
= set(
1117 ).difference(found_hops
[0])
1119 if additional_nexthops_in_required_nhs
:
1122 "%s is not active for route %s in "
1123 "RIB of router %s\n",
1124 additional_nexthops_in_required_nhs
,
1129 "Nexthop {} is not active"
1130 " for route {} in RIB of router"
1132 additional_nexthops_in_required_nhs
,
1141 elif next_hop
and fib
is None:
1142 if type(next_hop
) is not list:
1143 next_hop
= [next_hop
]
1146 for rib_r
in ospf_rib_json
[st_rt
]["nexthops"]
1150 missing_list_of_nexthops
= set(
1152 ).difference(next_hop
)
1153 additional_nexthops_in_required_nhs
= set(
1155 ).difference(found_hops
)
1157 if additional_nexthops_in_required_nhs
:
1159 "Missing nexthop %s for route"
1160 " %s in RIB of router %s\n",
1161 additional_nexthops_in_required_nhs
,
1166 "Nexthop {} is Missing for "
1167 "route {} in RIB of router {}\n".format(
1168 additional_nexthops_in_required_nhs
,
1177 if "routeType" not in ospf_rib_json
[st_rt
]:
1179 "[DUT: {}]: routeType missing"
1180 " for route {} in OSPF RIB \n".format(
1185 elif _rtype
!= ospf_rib_json
[st_rt
]["routeType"]:
1187 "[DUT: {}]: routeType mismatch"
1188 " for route {} in OSPF RIB \n".format(
1195 "[DUT: {}]: Found routeType {}"
1196 " for route {}".format(dut
, _rtype
, st_rt
)
1199 if "tag" not in ospf_rib_json
[st_rt
]:
1201 "[DUT: {}]: tag is not"
1203 " route {} in RIB \n".format(dut
, st_rt
)
1207 if _tag
!= ospf_rib_json
[st_rt
]["tag"]:
1209 "[DUT: {}]: tag value {}"
1210 " is not matched for"
1211 " route {} in RIB \n".format(
1219 if metric
is not None:
1220 if "type2cost" not in ospf_rib_json
[st_rt
]:
1222 "[DUT: {}]: metric is"
1224 " route {} in RIB \n".format(dut
, st_rt
)
1228 if metric
!= ospf_rib_json
[st_rt
]["type2cost"]:
1230 "[DUT: {}]: metric value "
1231 "{} is not matched for "
1232 "route {} in RIB \n".format(
1241 missing_routes
.append(st_rt
)
1245 "[DUT: {}]: Found next_hop {} for all OSPF"
1246 " routes in RIB".format(router
, next_hop
)
1249 if len(missing_routes
) > 0:
1250 errormsg
= "[DUT: {}]: Missing route in RIB, " "routes: {}".format(
1257 "[DUT: %s]: Verified routes in RIB, found" " routes are: %s\n",
1263 logger
.info("Exiting lib API: verify_ospf_rib()")
1267 @retry(retry_timeout
=20)
1268 def verify_ospf_interface(
1269 tgen
, topo
=None, dut
=None, lan
=False, input_dict
=None, expected
=True
1272 This API is to verify ospf routes by running
1273 show ip ospf interface command.
1277 * `tgen` : Topogen object
1278 * `topo` : topology descriptions
1279 * `dut`: device under test
1280 * `lan`: if set to true this interface belongs to LAN.
1281 * `input_dict` : Input dict data, required when configuring from testcase
1282 * `expected` : expected results from API, by-default True
1294 'mcastMemberOspfDesignatedRouters': True,
1295 'mcastMemberOspfAllRouters': True,
1296 'ospfEnabled': True,
1303 result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
1307 True or False (Error Message)
1310 logger
.debug("Entering lib API: verify_ospf_interface()")
1313 topo
= tgen
.json_topo
1315 for router
, rnode
in tgen
.routers().items():
1316 if "ospf" not in topo
["routers"][router
]:
1319 if dut
is not None and dut
!= router
:
1322 logger
.info("Verifying OSPF interface on router %s:", router
)
1323 show_ospf_json
= run_frr_cmd(rnode
, "show ip ospf interface json", isjson
=True)
1325 # Verifying output dictionary show_ospf_json is empty or not
1326 if not bool(show_ospf_json
):
1327 errormsg
= "OSPF is not running"
1330 # To find neighbor ip type
1331 ospf_intf_data
= input_dict
[router
]["links"]
1332 for ospf_intf
, intf_data
in ospf_intf_data
.items():
1333 intf
= topo
["routers"][router
]["links"][ospf_intf
]["interface"]
1334 if intf
in show_ospf_json
["interfaces"]:
1335 for intf_attribute
in intf_data
["ospf"]:
1337 intf_data
["ospf"][intf_attribute
]
1338 == show_ospf_json
["interfaces"][intf
][intf_attribute
]
1341 "[DUT: %s] OSPF interface %s: %s is %s",
1345 intf_data
["ospf"][intf_attribute
],
1348 errormsg
= "[DUT: {}] OSPF interface {}: {} is {}, \
1349 Expected is {}".format(
1353 intf_data
["ospf"][intf_attribute
],
1354 show_ospf_json
["interfaces"][intf
][intf_attribute
],
1358 logger
.debug("Exiting API: verify_ospf_interface()")
1362 @retry(retry_timeout
=40)
1363 def verify_ospf_database(
1364 tgen
, topo
, dut
, input_dict
, vrf
=None, lsatype
=None, rid
=None, expected
=True
1367 This API is to verify ospf lsa's by running
1368 show ip ospf database command.
1372 * `tgen` : Topogen object
1373 * `dut`: device under test
1374 * `input_dict` : Input dict data, required when configuring from testcase
1375 * `topo` : next to be verified
1376 * `expected` : expected results from API, by-default True
1383 "Router Link States": {
1384 "100.1.1.0-100.1.1.0": {
1385 "LSID": "100.1.1.0",
1386 "Advertised router": "100.1.1.0",
1388 "Sequence Number": "80000006",
1393 "Net Link States": {
1394 "10.0.0.2-100.1.1.1": {
1396 "Advertised router": "100.1.1.1",
1398 "Sequence Number": "80000001",
1405 result = verify_ospf_database(tgen, topo, dut, input_dict)
1409 True or False (Error Message)
1414 logger
.debug("Entering lib API: verify_ospf_database()")
1416 if "ospf" not in topo
["routers"][dut
]:
1417 errormsg
= "[DUT: {}] OSPF is not configured on the router.".format(dut
)
1420 rnode
= tgen
.routers()[dut
]
1422 logger
.info("Verifying OSPF interface on router %s:", dut
)
1425 rid
= "self-originate"
1428 command
= "show ip ospf database {} {} json".format(lsatype
, rid
)
1430 command
= "show ip ospf database {} {} vrf {} json".format(
1435 command
= "show ip ospf database json"
1437 command
= "show ip ospf database vrf {} json".format(vrf
)
1439 show_ospf_json
= run_frr_cmd(rnode
, command
, isjson
=True)
1440 # Verifying output dictionary show_ospf_json is empty or not
1441 if not bool(show_ospf_json
):
1442 errormsg
= "OSPF is not running"
1445 # for inter and inter lsa's
1446 ospf_db_data
= input_dict
.setdefault("areas", None)
1447 ospf_external_lsa
= input_dict
.setdefault("AS External Link States", None)
1448 # import pdb; pdb.set_trace()
1450 for ospf_area
, area_lsa
in ospf_db_data
.items():
1451 if ospf_area
in show_ospf_json
["routerLinkStates"]["areas"]:
1452 if "routerLinkStates" in area_lsa
:
1453 for lsa
in area_lsa
["routerLinkStates"]:
1454 _advrtr
= lsa
.setdefault("advertisedRouter", None)
1455 _options
= lsa
.setdefault("options", None)
1460 == show_ospf_json
["routerLinkStates"]["areas"][ospf_area
][
1464 == show_ospf_json
["routerLinkStates"]["areas"][ospf_area
][
1471 errormsg
= '[DUT: {}] OSPF LSA options: expected {}, Received Options are {} lsa["options"] {} OSPF LSAID: expected lsaid {}, Received lsaid {}'.format(
1473 show_ospf_json
["routerLinkStates"]["areas"][ospf_area
][
1478 show_ospf_json
["routerLinkStates"]["areas"][ospf_area
][
1484 if "Net Link States" in area_lsa
:
1485 for lsa
in area_lsa
["Net Link States"]:
1486 if lsa
in show_ospf_json
["areas"][ospf_area
]["Net Link States"]:
1488 "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
1496 "[DUT: {}] OSPF LSDB area {}: expected"
1497 " Network LSA is {}".format(router
, ospf_area
, lsa
)
1500 if "Summary Link States" in area_lsa
:
1501 for lsa
in area_lsa
["Summary Link States"]:
1504 in show_ospf_json
["areas"][ospf_area
]["Summary Link States"]
1507 "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
1515 "[DUT: {}] OSPF LSDB area {}: expected"
1516 " Summary LSA is {}".format(router
, ospf_area
, lsa
)
1519 if "ASBR-Summary Link States" in area_lsa
:
1520 for lsa
in area_lsa
["ASBR-Summary Link States"]:
1523 in show_ospf_json
["areas"][ospf_area
][
1524 "ASBR-Summary Link States"
1528 "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
1536 "[DUT: {}] OSPF LSDB area {}: expected"
1537 " ASBR Summary LSA is {}".format(router
, ospf_area
, lsa
)
1540 if ospf_external_lsa
:
1541 for ospf_ext_lsa
, ext_lsa_data
in ospf_external_lsa
.items():
1542 if ospf_ext_lsa
in show_ospf_json
["AS External Link States"]:
1544 "[DUT: %s] OSPF LSDB:External LSA %s", router
, ospf_ext_lsa
1549 "[DUT: {}] OSPF LSDB : expected"
1550 " External LSA is {}".format(router
, ospf_ext_lsa
)
1554 logger
.debug("Exiting API: verify_ospf_database()")
1558 @retry(retry_timeout
=20)
1559 def verify_ospf_summary(tgen
, topo
, dut
, input_dict
, ospf
=None, expected
=True):
1561 This API is to verify ospf routes by running
1562 show ip ospf interface command.
1566 * `tgen` : Topogen object
1567 * `topo` : topology descriptions
1568 * `dut`: device under test
1569 * `input_dict` : Input dict data, required when configuring from testcase
1575 "summaryAddress": "11.0.0.0/8",
1579 "externalRouteCount": 5
1582 result = verify_ospf_summary(tgen, topo, dut, input_dict)
1586 True or False (Error Message)
1589 logger
.debug("Entering lib API: {}".format(sys
._getframe
().f_code
.co_name
))
1593 logger
.info("Verifying OSPF summary on router %s:", router
)
1595 rnode
= tgen
.routers()[dut
]
1598 if "ospf6" not in topo
["routers"][dut
]:
1599 errormsg
= "[DUT: {}] OSPF6 is not configured on the router.".format(router
)
1602 show_ospf_json
= run_frr_cmd(
1603 rnode
, "show ipv6 ospf summary detail json", isjson
=True
1606 if "ospf" not in topo
["routers"][dut
]:
1607 errormsg
= "[DUT: {}] OSPF is not configured on the router.".format(router
)
1610 show_ospf_json
= run_frr_cmd(
1611 rnode
, "show ip ospf summary detail json", isjson
=True
1614 # Verifying output dictionary show_ospf_json is empty or not
1615 if not bool(show_ospf_json
):
1616 errormsg
= "OSPF is not running"
1619 # To find neighbor ip type
1620 ospf_summary_data
= input_dict
1623 show_ospf_json
= show_ospf_json
["default"]
1625 for ospf_summ
, summ_data
in ospf_summary_data
.items():
1626 if ospf_summ
not in show_ospf_json
:
1628 summary
= ospf_summary_data
[ospf_summ
]["summaryAddress"]
1630 if summary
in show_ospf_json
:
1631 for summ
in summ_data
:
1632 if summ_data
[summ
] == show_ospf_json
[summary
][summ
]:
1634 "[DUT: %s] OSPF summary %s:%s is %s",
1643 "[DUT: {}] OSPF summary {} : {} is {}, "
1644 "Expected is {}".format(
1648 show_ospf_json
[summary
][summ
],
1654 logger
.debug("Exiting lib API: {}".format(sys
._getframe
().f_code
.co_name
))
1658 @retry(retry_timeout
=30)
1659 def verify_ospf6_rib(
1660 tgen
, dut
, input_dict
, next_hop
=None, tag
=None, metric
=None, fib
=None
1663 This API is to verify ospf routes by running
1664 show ip ospf route command.
1668 * `tgen` : Topogen object
1669 * `dut`: device under test
1670 * `input_dict` : Input dict data, required when configuring from testcase
1671 * `next_hop` : next to be verified
1672 * `tag` : tag to be verified
1673 * `metric` : metric to be verified
1674 * `fib` : True if the route is installed in FIB.
1690 result = verify_ospf6_rib(tgen, dut, input_dict,next_hop=nh)
1694 True or False (Error Message)
1697 logger
.debug("Entering lib API: {}".format(sys
._getframe
().f_code
.co_name
))
1699 router_list
= tgen
.routers()
1700 additional_nexthops_in_required_nhs
= []
1702 for routerInput
in input_dict
.keys():
1703 for router
, rnode
in router_list
.items():
1707 logger
.info("Checking router %s RIB:", router
)
1709 # Verifying RIB routes
1710 command
= "show ipv6 ospf route detail"
1716 "static_routes" in input_dict
[routerInput
]
1717 or "prefix" in input_dict
[routerInput
]
1719 if "prefix" in input_dict
[routerInput
]:
1720 static_routes
= input_dict
[routerInput
]["prefix"]
1722 static_routes
= input_dict
[routerInput
]["static_routes"]
1724 for static_route
in static_routes
:
1725 cmd
= "{}".format(command
)
1727 cmd
= "{} json".format(cmd
)
1729 ospf_rib_json
= run_frr_cmd(rnode
, cmd
, isjson
=True)
1731 # Fix for PR 2644182
1733 ospf_rib_json
= ospf_rib_json
["routes"]
1737 # Verifying output dictionary ospf_rib_json is not empty
1738 if bool(ospf_rib_json
) is False:
1740 "[DUT: {}] No routes found in OSPF6 route "
1741 "table".format(router
)
1745 network
= static_route
["network"]
1746 no_of_ip
= static_route
.setdefault("no_of_ip", 1)
1747 _tag
= static_route
.setdefault("tag", None)
1748 _rtype
= static_route
.setdefault("routeType", None)
1750 # Generating IPs for verification
1751 ip_list
= generate_ips(network
, no_of_ip
)
1752 if len(ip_list
) == 1:
1756 for st_rt
in ip_list
:
1757 st_rt
= str(ipaddress
.ip_network(frr_unicode(st_rt
)))
1759 _addr_type
= validate_ip_address(st_rt
)
1760 if _addr_type
!= "ipv6":
1763 if st_rt
in ospf_rib_json
:
1766 found_routes
.append(st_rt
)
1768 if fib
and next_hop
:
1769 if type(next_hop
) is not list:
1770 next_hop
= [next_hop
]
1772 for mnh
in range(0, len(ospf_rib_json
[st_rt
])):
1775 in ospf_rib_json
[st_rt
][mnh
]["nextHops"][0]
1780 for rib_r
in ospf_rib_json
[st_rt
][mnh
][
1787 missing_list_of_nexthops
= set(
1789 ).difference(next_hop
)
1790 additional_nexthops_in_required_nhs
= set(
1792 ).difference(found_hops
[0])
1794 if additional_nexthops_in_required_nhs
:
1797 "%s is not active for route %s in "
1798 "RIB of router %s\n",
1799 additional_nexthops_in_required_nhs
,
1804 "Nexthop {} is not active"
1805 " for route {} in RIB of router"
1807 additional_nexthops_in_required_nhs
,
1816 elif next_hop
and fib
is None:
1817 if type(next_hop
) is not list:
1818 next_hop
= [next_hop
]
1821 for rib_r
in ospf_rib_json
[st_rt
]["nextHops"]
1825 missing_list_of_nexthops
= set(
1827 ).difference(next_hop
)
1828 additional_nexthops_in_required_nhs
= set(
1830 ).difference(found_hops
)
1831 if additional_nexthops_in_required_nhs
:
1833 "Missing nexthop %s for route"
1834 " %s in RIB of router %s\n",
1835 additional_nexthops_in_required_nhs
,
1840 "Nexthop {} is Missing for "
1841 "route {} in RIB of router {}\n".format(
1842 additional_nexthops_in_required_nhs
,
1851 if "destinationType" not in ospf_rib_json
[st_rt
]:
1853 "[DUT: {}]: destinationType missing"
1854 "for route {} in OSPF RIB \n".format(dut
, st_rt
)
1857 elif _rtype
!= ospf_rib_json
[st_rt
]["destinationType"]:
1859 "[DUT: {}]: destinationType mismatch"
1860 "for route {} in OSPF RIB \n".format(dut
, st_rt
)
1865 "DUT: {}]: Found destinationType {}"
1866 "for route {}".format(dut
, _rtype
, st_rt
)
1869 if "tag" not in ospf_rib_json
[st_rt
]:
1871 "[DUT: {}]: tag is not"
1873 " route {} in RIB \n".format(dut
, st_rt
)
1877 if _tag
!= ospf_rib_json
[st_rt
]["tag"]:
1879 "[DUT: {}]: tag value {}"
1880 " is not matched for"
1881 " route {} in RIB \n".format(
1889 if metric
is not None:
1890 if "metricCostE2" not in ospf_rib_json
[st_rt
]:
1892 "[DUT: {}]: metric is"
1894 " route {} in RIB \n".format(dut
, st_rt
)
1898 if metric
!= ospf_rib_json
[st_rt
]["metricCostE2"]:
1900 "[DUT: {}]: metric value "
1901 "{} is not matched for "
1902 "route {} in RIB \n".format(
1911 missing_routes
.append(st_rt
)
1915 "[DUT: {}]: Found next_hop {} for all OSPF"
1916 " routes in RIB".format(router
, next_hop
)
1919 if len(missing_routes
) > 0:
1920 errormsg
= "[DUT: {}]: Missing route in RIB, " "routes: {}".format(
1927 "[DUT: %s]: Verified routes in RIB, found" " routes are: %s\n",
1933 logger
.debug("Exiting lib API: {}".format(sys
._getframe
().f_code
.co_name
))
1937 @retry(retry_timeout
=6)
1938 def verify_ospf6_interface(tgen
, topo
=None, dut
=None, lan
=False, input_dict
=None):
1940 This API is to verify ospf routes by running
1941 show ip ospf interface command.
1945 * `tgen` : Topogen object
1946 * `topo` : topology descriptions
1947 * `dut`: device under test
1948 * `lan`: if set to true this interface belongs to LAN.
1949 * `input_dict` : Input dict data, required when configuring from testcase
1961 'mcastMemberOspfDesignatedRouters': True,
1962 'mcastMemberOspfAllRouters': True,
1963 'ospfEnabled': True,
1970 result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
1974 True or False (Error Message)
1977 logger
.debug("Entering lib API: verify_ospf6_interface")
1981 topo
= tgen
.json_topo
1983 for router
, rnode
in tgen
.routers().items():
1984 if "ospf6" not in topo
["routers"][router
]:
1987 if dut
is not None and dut
!= router
:
1990 logger
.info("Verifying OSPF interface on router %s:", router
)
1991 show_ospf_json
= run_frr_cmd(
1992 rnode
, "show ipv6 ospf interface json", isjson
=True
1995 # Verifying output dictionary show_ospf_json is empty or not
1996 if not bool(show_ospf_json
):
1997 errormsg
= "OSPF6 is not running"
2000 # To find neighbor ip type
2001 ospf_intf_data
= input_dict
[router
]["links"]
2002 for ospf_intf
, intf_data
in ospf_intf_data
.items():
2003 intf
= topo
["routers"][router
]["links"][ospf_intf
]["interface"]
2004 if intf
in show_ospf_json
:
2005 for intf_attribute
in intf_data
["ospf6"]:
2006 if intf_data
["ospf6"][intf_attribute
] is not list:
2008 intf_data
["ospf6"][intf_attribute
]
2009 == show_ospf_json
[intf
][intf_attribute
]
2012 "[DUT: %s] OSPF6 interface %s: %s is %s",
2016 intf_data
["ospf6"][intf_attribute
],
2018 elif intf_data
["ospf6"][intf_attribute
] is list:
2019 for addr_list
in len(show_ospf_json
[intf
][intf_attribute
]):
2021 show_ospf_json
[intf
][intf_attribute
][addr_list
][
2024 == intf_data
["ospf6"]["internetAddress"][0]["address"]
2028 errormsg
= "[DUT: {}] OSPF6 interface {}: {} is {}, \
2029 Expected is {}".format(
2033 intf_data
["ospf6"][intf_attribute
],
2034 intf_data
["ospf6"][intf_attribute
],
2038 errormsg
= "[DUT: {}] OSPF6 interface {}: {} is {}, \
2039 Expected is {}".format(
2043 intf_data
["ospf6"][intf_attribute
],
2044 intf_data
["ospf6"][intf_attribute
],
2048 logger
.debug("Exiting lib API: {}".format(sys
._getframe
().f_code
.co_name
))
2052 @retry(retry_timeout
=20)
2053 def verify_ospf6_database(tgen
, topo
, dut
, input_dict
):
2055 This API is to verify ospf lsa's by running
2056 show ip ospf database command.
2060 * `tgen` : Topogen object
2061 * `dut`: device under test
2062 * `input_dict` : Input dict data, required when configuring from testcase
2063 * `topo` : next to be verified
2070 "routerLinkStates": {
2071 "100.1.1.0-100.1.1.0": {
2072 "LSID": "100.1.1.0",
2073 "Advertised router": "100.1.1.0",
2075 "Sequence Number": "80000006",
2080 "networkLinkStates": {
2081 "10.0.0.2-100.1.1.1": {
2083 "Advertised router": "100.1.1.1",
2085 "Sequence Number": "80000001",
2092 result = verify_ospf_database(tgen, topo, dut, input_dict)
2096 True or False (Error Message)
2101 logger
.debug("Entering lib API: {}".format(sys
._getframe
().f_code
.co_name
))
2103 if "ospf" not in topo
["routers"][dut
]:
2104 errormsg
= "[DUT: {}] OSPF is not configured on the router.".format(dut
)
2107 rnode
= tgen
.routers()[dut
]
2109 logger
.info("Verifying OSPF interface on router %s:", dut
)
2110 show_ospf_json
= run_frr_cmd(rnode
, "show ip ospf database json", isjson
=True)
2111 # Verifying output dictionary show_ospf_json is empty or not
2112 if not bool(show_ospf_json
):
2113 errormsg
= "OSPF is not running"
2116 # for inter and inter lsa's
2117 ospf_db_data
= input_dict
.setdefault("areas", None)
2118 ospf_external_lsa
= input_dict
.setdefault("asExternalLinkStates", None)
2121 for ospf_area
, area_lsa
in ospf_db_data
.items():
2122 if ospf_area
in show_ospf_json
["areas"]:
2123 if "routerLinkStates" in area_lsa
:
2124 for lsa
in area_lsa
["routerLinkStates"]:
2125 for rtrlsa
in show_ospf_json
["areas"][ospf_area
][
2129 lsa
["lsaId"] == rtrlsa
["lsaId"]
2130 and lsa
["advertisedRouter"]
2131 == rtrlsa
["advertisedRouter"]
2137 "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
2145 "[DUT: {}] OSPF LSDB area {}: expected"
2146 " Router LSA is {}".format(router
, ospf_area
, lsa
)
2150 if "networkLinkStates" in area_lsa
:
2151 for lsa
in area_lsa
["networkLinkStates"]:
2152 for netlsa
in show_ospf_json
["areas"][ospf_area
][
2157 in show_ospf_json
["areas"][ospf_area
][
2162 lsa
["lsaId"] == netlsa
["lsaId"]
2163 and lsa
["advertisedRouter"]
2164 == netlsa
["advertisedRouter"]
2170 "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
2178 "[DUT: {}] OSPF LSDB area {}: expected"
2179 " Network LSA is {}".format(router
, ospf_area
, lsa
)
2183 if "summaryLinkStates" in area_lsa
:
2184 for lsa
in area_lsa
["summaryLinkStates"]:
2185 for t3lsa
in show_ospf_json
["areas"][ospf_area
][
2189 lsa
["lsaId"] == t3lsa
["lsaId"]
2190 and lsa
["advertisedRouter"] == t3lsa
["advertisedRouter"]
2196 "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
2204 "[DUT: {}] OSPF LSDB area {}: expected"
2205 " Summary LSA is {}".format(router
, ospf_area
, lsa
)
2209 if "nssaExternalLinkStates" in area_lsa
:
2210 for lsa
in area_lsa
["nssaExternalLinkStates"]:
2211 for t7lsa
in show_ospf_json
["areas"][ospf_area
][
2212 "nssaExternalLinkStates"
2215 lsa
["lsaId"] == t7lsa
["lsaId"]
2216 and lsa
["advertisedRouter"] == t7lsa
["advertisedRouter"]
2222 "[DUT: %s] OSPF LSDB area %s:Type7 " "LSA %s",
2230 "[DUT: {}] OSPF LSDB area {}: expected"
2231 " Type7 LSA is {}".format(router
, ospf_area
, lsa
)
2235 if "asbrSummaryLinkStates" in area_lsa
:
2236 for lsa
in area_lsa
["asbrSummaryLinkStates"]:
2237 for t4lsa
in show_ospf_json
["areas"][ospf_area
][
2238 "asbrSummaryLinkStates"
2241 lsa
["lsaId"] == t4lsa
["lsaId"]
2242 and lsa
["advertisedRouter"] == t4lsa
["advertisedRouter"]
2248 "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
2256 "[DUT: {}] OSPF LSDB area {}: expected"
2257 " ASBR Summary LSA is {}".format(router
, ospf_area
, lsa
)
2261 if "linkLocalOpaqueLsa" in area_lsa
:
2262 for lsa
in area_lsa
["linkLocalOpaqueLsa"]:
2264 for lnklsa
in show_ospf_json
["areas"][ospf_area
][
2265 "linkLocalOpaqueLsa"
2268 lsa
["lsaId"] in lnklsa
["lsaId"]
2269 and "linkLocalOpaqueLsa"
2270 in show_ospf_json
["areas"][ospf_area
]
2274 "[DUT: FRR] OSPF LSDB area %s:Opaque-LSA"
2283 "[DUT: FRR] OSPF LSDB area: {} "
2284 "expected Opaque-LSA is {}, Found is {}".format(
2285 ospf_area
, lsa
, show_ospf_json
2288 raise ValueError(errormsg
)
2291 errormsg
= "[DUT: FRR] linkLocalOpaqueLsa Not " "present"
2294 if ospf_external_lsa
:
2295 for lsa
in ospf_external_lsa
:
2297 for t5lsa
in show_ospf_json
["asExternalLinkStates"]:
2299 lsa
["lsaId"] == t5lsa
["lsaId"]
2300 and lsa
["advertisedRouter"] == t5lsa
["advertisedRouter"]
2307 logger
.info("[DUT: %s] OSPF LSDB:External LSA %s", router
, lsa
)
2311 "[DUT: {}] OSPF LSDB : expected"
2312 " External LSA is {}".format(router
, lsa
)
2316 logger
.debug("Exiting lib API: {}".format(sys
._getframe
().f_code
.co_name
))
2320 def config_ospf6_interface(
2321 tgen
, topo
=None, input_dict
=None, build
=False, load_config
=True
2324 API to configure ospf on router.
2328 * `tgen` : Topogen object
2329 * `topo` : json file data
2330 * `input_dict` : Input dict data, required when configuring from testcase
2331 * `build` : Only for initial setup phase this is set as True.
2332 * `load_config` : Loading the config to router this is set as True.
2341 "authentication": 'message-digest',
2342 "authentication-key": "ospf",
2343 "message-digest-key": "10"
2349 result = config_ospf6_interface(tgen, topo, r1_ospf_auth)
2356 logger
.debug("Entering lib API: {}".format(sys
._getframe
().f_code
.co_name
))
2359 topo
= tgen
.json_topo
2362 input_dict
= deepcopy(topo
)
2364 input_dict
= deepcopy(input_dict
)
2366 config_data_dict
= {}
2368 for router
in input_dict
.keys():
2370 for lnk
in input_dict
[router
]["links"].keys():
2371 if "ospf6" not in input_dict
[router
]["links"][lnk
]:
2373 "Router %s: ospf6 config is not present in"
2374 "input_dict, passed input_dict %s",
2379 ospf_data
= input_dict
[router
]["links"][lnk
]["ospf6"]
2380 data_ospf_area
= ospf_data
.setdefault("area", None)
2381 data_ospf_auth
= ospf_data
.setdefault("hash-algo", None)
2382 data_ospf_keychain
= ospf_data
.setdefault("keychain", None)
2383 data_ospf_dr_priority
= ospf_data
.setdefault("priority", None)
2384 data_ospf_cost
= ospf_data
.setdefault("cost", None)
2385 data_ospf_mtu
= ospf_data
.setdefault("mtu_ignore", None)
2388 intf
= topo
["routers"][router
]["links"][lnk
]["interface"]
2390 intf
= topo
["switches"][router
]["links"][lnk
]["interface"]
2393 cmd
= "interface {}".format(intf
)
2395 config_data
.append(cmd
)
2396 # interface area config
2398 cmd
= "ipv6 ospf area {}".format(data_ospf_area
)
2399 config_data
.append(cmd
)
2401 # interface ospf auth
2403 cmd
= "ipv6 ospf6 authentication"
2405 if "del_action" in ospf_data
:
2406 cmd
= "no {}".format(cmd
)
2408 if "hash-algo" in ospf_data
:
2409 cmd
= "{} key-id {} hash-algo {} key {}".format(
2411 ospf_data
["key-id"],
2412 ospf_data
["hash-algo"],
2415 config_data
.append(cmd
)
2417 # interface ospf auth with keychain
2418 if data_ospf_keychain
:
2419 cmd
= "ipv6 ospf6 authentication"
2421 if "del_action" in ospf_data
:
2422 cmd
= "no {}".format(cmd
)
2424 if "keychain" in ospf_data
:
2425 cmd
= "{} keychain {}".format(cmd
, ospf_data
["keychain"])
2426 config_data
.append(cmd
)
2428 # interface ospf dr priority
2429 if data_ospf_dr_priority
:
2430 cmd
= "ipv6 ospf priority {}".format(ospf_data
["priority"])
2431 if "del_action" in ospf_data
:
2432 cmd
= "no {}".format(cmd
)
2433 config_data
.append(cmd
)
2435 # interface ospf cost
2437 cmd
= "ipv6 ospf cost {}".format(ospf_data
["cost"])
2438 if "del_action" in ospf_data
:
2439 cmd
= "no {}".format(cmd
)
2440 config_data
.append(cmd
)
2442 # interface ospf mtu
2444 cmd
= "ipv6 ospf mtu-ignore"
2445 if "del_action" in ospf_data
:
2446 cmd
= "no {}".format(cmd
)
2447 config_data
.append(cmd
)
2453 config_data_dict
[router
] = config_data
2455 result
= create_common_configurations(
2456 tgen
, config_data_dict
, "interface_config", build
=build
2459 logger
.debug("Exiting lib API: {}".format(sys
._getframe
().f_code
.co_name
))
2463 @retry(retry_timeout
=20)
2464 def verify_ospf_gr_helper(tgen
, topo
, dut
, input_dict
=None):
2466 This API is used to vreify gr helper using command
2467 show ip ospf graceful-restart helper
2471 * `tgen` : Topogen object
2472 * `topo` : topology descriptions
2474 * 'input_dict' - values to be verified
2479 "helperSupport":"Disabled",
2480 "strictLsaCheck":"Enabled",
2481 "restartSupport":"Planned and Unplanned Restarts",
2482 "supportedGracePeriod":1800
2484 result = verify_ospf_gr_helper(tgen, topo, dut, input_dict)
2487 logger
.debug("Entering lib API: {}".format(sys
._getframe
().f_code
.co_name
))
2490 if "ospf" not in topo
["routers"][dut
]:
2491 errormsg
= "[DUT: {}] OSPF is not configured on the router.".format(dut
)
2494 rnode
= tgen
.routers()[dut
]
2495 logger
.info("Verifying OSPF GR details on router %s:", dut
)
2496 show_ospf_json
= run_frr_cmd(
2497 rnode
, "show ip ospf graceful-restart helper json", isjson
=True
2500 # Verifying output dictionary show_ospf_json is empty or not
2501 if not bool(show_ospf_json
):
2502 errormsg
= "OSPF is not running"
2503 raise ValueError(errormsg
)
2506 for ospf_gr
, gr_data
in input_dict
.items():
2508 if input_dict
[ospf_gr
] == show_ospf_json
[ospf_gr
]:
2510 "[DUT: FRR] OSPF GR Helper: %s is %s",
2512 show_ospf_json
[ospf_gr
],
2517 "[DUT: FRR] OSPF GR Helper: {} expected is {}, Found "
2519 ospf_gr
, input_dict
[ospf_gr
], show_ospf_json
[ospf_gr
]
2522 raise ValueError(errormsg
)
2526 errormsg
= "[DUT: FRR] OSPF GR Helper: {}".format(ospf_gr
)
2529 logger
.debug("Exiting lib API: {}".format(sys
._getframe
().f_code
.co_name
))
2533 def get_ospf_database(tgen
, topo
, dut
, input_dict
, vrf
=None, lsatype
=None, rid
=None):
2535 This API is to return ospf lsa's by running
2536 show ip ospf database command.
2540 * `tgen` : Topogen object
2541 * `dut`: device under test
2542 * `input_dict` : Input dict data, required when configuring from testcase
2543 * `topo` : next to be verified
2544 * `vrf` : vrf to be checked
2545 * `lsatype` : type of lsa to be checked
2546 * `rid` : router id for lsa to be checked
2552 "routerLinkStates": {
2553 "100.1.1.0-100.1.1.0": {
2554 "LSID": "100.1.1.0",
2555 "Advertised router": "100.1.1.0",
2557 "Sequence Number": "80000006",
2562 "networkLinkStates": {
2563 "10.0.0.2-100.1.1.1": {
2565 "Advertised router": "100.1.1.1",
2567 "Sequence Number": "80000001",
2574 result = get_ospf_database(tgen, topo, dut, input_dict)
2578 True or False (Error Message)
2583 logger
.debug("Entering lib API: {}".format(sys
._getframe
().f_code
.co_name
))
2585 if "ospf" not in topo
["routers"][dut
]:
2586 errormsg
= "[DUT: {}] OSPF is not configured on the router.".format(dut
)
2589 rnode
= tgen
.routers()[dut
]
2591 logger
.info("Verifying OSPF interface on router %s:", dut
)
2593 rid
= "self-originate"
2596 command
= "show ip ospf database {} {} json".format(lsatype
, rid
)
2598 command
= "show ip ospf database {} {} vrf {} json".format(
2603 command
= "show ip ospf database json"
2605 command
= "show ip ospf database vrf {} json".format(vrf
)
2607 show_ospf_json
= run_frr_cmd(rnode
, command
, isjson
=True)
2608 # Verifying output dictionary show_ospf_json is empty or not
2609 if not bool(show_ospf_json
):
2610 errormsg
= "OSPF is not running"
2613 # for inter and inter lsa's
2614 ospf_db_data
= input_dict
.setdefault("areas", None)
2615 ospf_external_lsa
= input_dict
.setdefault("asExternalLinkStates", None)
2618 for ospf_area
, area_lsa
in ospf_db_data
.items():
2619 if "areas" in show_ospf_json
and ospf_area
in show_ospf_json
["areas"]:
2620 if "routerLinkStates" in area_lsa
:
2621 for lsa
in area_lsa
["routerLinkStates"]:
2622 for rtrlsa
in show_ospf_json
["areas"][ospf_area
][
2625 _advrtr
= lsa
.setdefault("advertisedRouter", None)
2626 _options
= lsa
.setdefault("options", None)
2629 and lsa
["lsaId"] == rtrlsa
["lsaId"]
2630 and lsa
["advertisedRouter"]
2631 == rtrlsa
["advertisedRouter"]
2637 and lsa
["lsaId"] == rtrlsa
["lsaId"]
2638 and lsa
["options"] == rtrlsa
["options"]
2645 "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
2653 "[DUT: {}] OSPF LSDB area {}: expected"
2654 " Router LSA is {}\n found Router LSA: {}".format(
2655 router
, ospf_area
, lsa
, rtrlsa
2660 if "networkLinkStates" in area_lsa
:
2661 for lsa
in area_lsa
["networkLinkStates"]:
2662 for netlsa
in show_ospf_json
["areas"][ospf_area
][
2667 in show_ospf_json
["areas"][ospf_area
][
2672 lsa
["lsaId"] == netlsa
["lsaId"]
2673 and lsa
["advertisedRouter"]
2674 == netlsa
["advertisedRouter"]
2680 "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
2688 "[DUT: {}] OSPF LSDB area {}: expected"
2689 " Network LSA is {}".format(router
, ospf_area
, lsa
)
2693 if "summaryLinkStates" in area_lsa
:
2694 for lsa
in area_lsa
["summaryLinkStates"]:
2695 for t3lsa
in show_ospf_json
["areas"][ospf_area
][
2699 lsa
["lsaId"] == t3lsa
["lsaId"]
2700 and lsa
["advertisedRouter"] == t3lsa
["advertisedRouter"]
2706 "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
2714 "[DUT: {}] OSPF LSDB area {}: expected"
2715 " Summary LSA is {}".format(router
, ospf_area
, lsa
)
2719 if "nssaExternalLinkStates" in area_lsa
:
2720 for lsa
in area_lsa
["nssaExternalLinkStates"]:
2721 for t7lsa
in show_ospf_json
["areas"][ospf_area
][
2722 "nssaExternalLinkStates"
2725 lsa
["lsaId"] == t7lsa
["lsaId"]
2726 and lsa
["advertisedRouter"] == t7lsa
["advertisedRouter"]
2732 "[DUT: %s] OSPF LSDB area %s:Type7 " "LSA %s",
2740 "[DUT: {}] OSPF LSDB area {}: expected"
2741 " Type7 LSA is {}".format(router
, ospf_area
, lsa
)
2745 if "asbrSummaryLinkStates" in area_lsa
:
2746 for lsa
in area_lsa
["asbrSummaryLinkStates"]:
2747 for t4lsa
in show_ospf_json
["areas"][ospf_area
][
2748 "asbrSummaryLinkStates"
2751 lsa
["lsaId"] == t4lsa
["lsaId"]
2752 and lsa
["advertisedRouter"] == t4lsa
["advertisedRouter"]
2758 "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
2766 "[DUT: {}] OSPF LSDB area {}: expected"
2767 " ASBR Summary LSA is {}".format(router
, ospf_area
, lsa
)
2771 if "linkLocalOpaqueLsa" in area_lsa
:
2772 for lsa
in area_lsa
["linkLocalOpaqueLsa"]:
2774 for lnklsa
in show_ospf_json
["areas"][ospf_area
][
2775 "linkLocalOpaqueLsa"
2778 lsa
["lsaId"] in lnklsa
["lsaId"]
2779 and "linkLocalOpaqueLsa"
2780 in show_ospf_json
["areas"][ospf_area
]
2784 "[DUT: FRR] OSPF LSDB area %s:Opaque-LSA"
2793 "[DUT: FRR] OSPF LSDB area: {} "
2794 "expected Opaque-LSA is {}, Found is {}".format(
2795 ospf_area
, lsa
, show_ospf_json
2798 raise ValueError(errormsg
)
2801 errormsg
= "[DUT: FRR] linkLocalOpaqueLsa Not " "present"
2804 if "routerLinkStates" in area_lsa
:
2805 for lsa
in area_lsa
["routerLinkStates"]:
2806 for rtrlsa
in show_ospf_json
["routerLinkStates"]:
2807 _advrtr
= lsa
.setdefault("advertisedRouter", None)
2808 _options
= lsa
.setdefault("options", None)
2809 _age
= lsa
.setdefault("lsaAge", None)
2813 == show_ospf_json
["routerLinkStates"][rtrlsa
][
2822 == show_ospf_json
["routerLinkStates"][rtrlsa
][
2831 show_ospf_json
["routerLinkStates"][rtrlsa
][
2837 "[DUT: %s] OSPF LSDB area %s:Router " "LSA %s",
2845 "[DUT: {}] OSPF LSDB area {}: expected"
2846 " Router LSA is {}\n found Router LSA: {}".format(
2850 show_ospf_json
["routerLinkStates"],
2855 if "networkLinkStates" in area_lsa
:
2856 for lsa
in area_lsa
["networkLinkStates"]:
2857 for netlsa
in show_ospf_json
["areas"][ospf_area
][
2862 in show_ospf_json
["areas"][ospf_area
][
2867 lsa
["lsaId"] == netlsa
["lsaId"]
2868 and lsa
["advertisedRouter"]
2869 == netlsa
["advertisedRouter"]
2875 "[DUT: %s] OSPF LSDB area %s:Network " "LSA %s",
2883 "[DUT: {}] OSPF LSDB area {}: expected"
2884 " Network LSA is {}".format(router
, ospf_area
, lsa
)
2888 if "summaryLinkStates" in area_lsa
:
2889 for lsa
in area_lsa
["summaryLinkStates"]:
2890 for t3lsa
in show_ospf_json
["areas"][ospf_area
][
2894 lsa
["lsaId"] == t3lsa
["lsaId"]
2895 and lsa
["advertisedRouter"] == t3lsa
["advertisedRouter"]
2901 "[DUT: %s] OSPF LSDB area %s:Summary " "LSA %s",
2909 "[DUT: {}] OSPF LSDB area {}: expected"
2910 " Summary LSA is {}".format(router
, ospf_area
, lsa
)
2914 if "nssaExternalLinkStates" in area_lsa
:
2915 for lsa
in area_lsa
["nssaExternalLinkStates"]:
2916 for t7lsa
in show_ospf_json
["areas"][ospf_area
][
2917 "nssaExternalLinkStates"
2920 lsa
["lsaId"] == t7lsa
["lsaId"]
2921 and lsa
["advertisedRouter"] == t7lsa
["advertisedRouter"]
2927 "[DUT: %s] OSPF LSDB area %s:Type7 " "LSA %s",
2935 "[DUT: {}] OSPF LSDB area {}: expected"
2936 " Type7 LSA is {}".format(router
, ospf_area
, lsa
)
2940 if "asbrSummaryLinkStates" in area_lsa
:
2941 for lsa
in area_lsa
["asbrSummaryLinkStates"]:
2942 for t4lsa
in show_ospf_json
["areas"][ospf_area
][
2943 "asbrSummaryLinkStates"
2946 lsa
["lsaId"] == t4lsa
["lsaId"]
2947 and lsa
["advertisedRouter"] == t4lsa
["advertisedRouter"]
2953 "[DUT: %s] OSPF LSDB area %s:ASBR Summary " "LSA %s",
2961 "[DUT: {}] OSPF LSDB area {}: expected"
2962 " ASBR Summary LSA is {}".format(router
, ospf_area
, lsa
)
2966 if "linkLocalOpaqueLsa" in area_lsa
:
2967 for lsa
in area_lsa
["linkLocalOpaqueLsa"]:
2969 for lnklsa
in show_ospf_json
["areas"][ospf_area
][
2970 "linkLocalOpaqueLsa"
2973 lsa
["lsaId"] in lnklsa
["lsaId"]
2974 and "linkLocalOpaqueLsa"
2975 in show_ospf_json
["areas"][ospf_area
]
2979 "[DUT: FRR] OSPF LSDB area %s:Opaque-LSA"
2988 "[DUT: FRR] OSPF LSDB area: {} "
2989 "expected Opaque-LSA is {}, Found is {}".format(
2990 ospf_area
, lsa
, show_ospf_json
2993 raise ValueError(errormsg
)
2996 errormsg
= "[DUT: FRR] linkLocalOpaqueLsa Not " "present"
2999 if ospf_external_lsa
:
3000 for lsa
in ospf_external_lsa
:
3002 for t5lsa
in show_ospf_json
["asExternalLinkStates"]:
3004 lsa
["lsaId"] == t5lsa
["lsaId"]
3005 and lsa
["advertisedRouter"] == t5lsa
["advertisedRouter"]
3012 logger
.info("[DUT: %s] OSPF LSDB:External LSA %s", router
, lsa
)
3016 "[DUT: {}] OSPF LSDB : expected"
3017 " External LSA is {}".format(router
, lsa
)
3021 logger
.debug("Exiting lib API: {}".format(sys
._getframe
().f_code
.co_name
))