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