Merge pull request #6814 from gpnaveen/ospf_basic_functionality

tests: ospf basic functionality topojson testcases.
This commit is contained in:
Donald Sharp 2020-09-18 21:20:04 -04:00 committed by GitHub
commit dfc51e66bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 7678 additions and 2 deletions

View File

@ -258,6 +258,7 @@ def create_common_configuration(
"route_maps": "! Route Maps Config\n",
"bgp": "! BGP Config\n",
"vrf": "! VRF Config\n",
"ospf": "! OSPF Config\n",
}
)
@ -684,7 +685,7 @@ def generate_support_bundle():
return True
def start_topology(tgen):
def start_topology(tgen, daemon=None):
"""
Starting topology, create tmp files which are loaded to routers
to start deamons and then start routers
@ -736,9 +737,16 @@ def start_topology(tgen):
router.load_config(
TopoRouter.RD_ZEBRA, "{}/{}/zebra.conf".format(TMPDIR, rname)
)
# Loading empty bgpd.conf file to router, to start the bgp deamon
router.load_config(TopoRouter.RD_BGP, "{}/{}/bgpd.conf".format(TMPDIR, rname))
if daemon and 'ospfd' in daemon:
# Loading empty ospf.conf file to router, to start the bgp deamon
router.load_config(
TopoRouter.RD_OSPF,
'{}/{}/ospfd.conf'.format(TMPDIR, rname)
)
# Starting routers
logger.info("Starting all routers once topology is created")
tgen.start_router()
@ -811,6 +819,24 @@ def number_to_column(routerName):
return ord(routerName[0]) - 97
def topo_daemons(tgen, topo):
"""
Returns daemon list required for the suite based on topojson.
"""
daemon_list = []
router_list = tgen.routers()
ROUTER_LIST = sorted(
router_list.keys(), key=lambda x: int(re_search("\d+", x).group(0))
)
for rtr in ROUTER_LIST:
if 'ospf' in topo['routers'][rtr] and 'ospfd' not in daemon_list:
daemon_list.append('ospfd')
return daemon_list
#############################################
# Common APIs, will be used by all protocols
#############################################
@ -1394,6 +1420,58 @@ def create_interfaces_cfg(tgen, topo, build=False):
else:
interface_data.append("ipv6 address {}\n".format(intf_addr))
if 'ospf' in data:
ospf_data = data['ospf']
if 'area' in ospf_data:
intf_ospf_area = c_data["links"][destRouterLink][
"ospf"]["area"]
if "delete" in data and data["delete"]:
interface_data.append("no ip ospf area")
else:
interface_data.append("ip ospf area {}".format(
intf_ospf_area
))
if "hello_interval" in ospf_data:
intf_ospf_hello = c_data["links"][destRouterLink][
"ospf"]["hello_interval"]
if "delete" in data and data["delete"]:
interface_data.append("no ip ospf "\
" hello-interval")
else:
interface_data.append("ip ospf "\
" hello-interval {}".format(intf_ospf_hello))
if "dead_interval" in ospf_data:
intf_ospf_dead = c_data["links"][destRouterLink][
"ospf"]["dead_interval"]
if "delete" in data and data["delete"]:
interface_data.append("no ip ospf"\
" dead-interval")
else:
interface_data.append("ip ospf "\
" dead-interval {}".format(intf_ospf_dead))
if "network" in ospf_data:
intf_ospf_nw = c_data["links"][destRouterLink][
"ospf"]["network"]
if "delete" in data and data["delete"]:
interface_data.append("no ip ospf"\
" network {}".format(intf_ospf_nw))
else:
interface_data.append("ip ospf"\
" network {}".format(intf_ospf_nw))
if "priority" in ospf_data:
intf_ospf_nw = c_data["links"][destRouterLink][
"ospf"]["priority"]
if "delete" in data and data["delete"]:
interface_data.append("no ip ospf"\
" priority")
else:
interface_data.append("ip ospf"\
" priority {}".format(intf_ospf_nw))
result = create_common_configuration(
tgen, c_router, interface_data, "interface_config", build=build
)

1182
tests/topotests/lib/ospf.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,9 @@ from json import dumps as json_dumps
from re import search as re_search
import ipaddress
import pytest
import ipaddr
from copy import deepcopy
# Import topogen and topotest helpers
from lib.topolog import logger
@ -41,7 +44,7 @@ from lib.common_config import (
)
from lib.bgp import create_router_bgp
from lib.ospf import create_router_ospf
ROUTER_LIST = []
@ -58,12 +61,27 @@ def build_topo_from_json(tgen, topo):
topo["routers"].keys(), key=lambda x: int(re_search("\d+", x).group(0))
)
SWITCH_LIST = []
if "switches" in topo:
SWITCH_LIST = sorted(
topo["switches"].keys(), key=lambda x: int(re_search("\d+", x).group(0))
)
listRouters = ROUTER_LIST[:]
listSwitches = SWITCH_LIST[:]
listAllRouters = deepcopy(listRouters)
dictSwitches = {}
for routerN in ROUTER_LIST:
logger.info("Topo: Add router {}".format(routerN))
tgen.add_router(routerN)
listRouters.append(routerN)
for switchN in SWITCH_LIST:
logger.info("Topo: Add switch {}".format(switchN))
dictSwitches[switchN] = tgen.add_switch(switchN)
listSwitches.append(switchN)
if "ipv4base" in topo:
ipv4Next = ipaddress.IPv4Address(topo["link_ip_start"]["ipv4"])
ipv4Step = 2 ** (32 - topo["link_ip_start"]["v4mask"])
@ -191,6 +209,72 @@ def build_topo_from_json(tgen, topo):
),
)
switch_count = 0
add_switch_to_topo = []
while listSwitches != []:
curSwitch = listSwitches.pop(0)
# Physical Interfaces
if "links" in topo['switches'][curSwitch]:
for destRouterLink, data in sorted(
topo['switches'][curSwitch]['links'].iteritems()):
# Loopback interfaces
if "dst_node" in data:
destRouter = data['dst_node']
elif "-" in destRouterLink:
# Spliting and storing destRouterLink data in tempList
tempList = destRouterLink.split("-")
# destRouter
destRouter = tempList.pop(0)
else:
destRouter = destRouterLink
if destRouter in listAllRouters:
topo['routers'][destRouter]['links'][curSwitch] = \
deepcopy(topo['switches'][curSwitch]['links'][destRouterLink])
# Assigning name to interfaces
topo['routers'][destRouter]['links'][curSwitch]['interface'] = \
'{}-{}-eth{}'.format(destRouter, curSwitch, topo['routers'] \
[destRouter]['nextIfname'])
topo['switches'][curSwitch]['links'][destRouter]['interface'] = \
'{}-{}-eth{}'.format(curSwitch, destRouter, topo['routers'] \
[destRouter]['nextIfname'])
topo['routers'][destRouter]['nextIfname'] += 1
# Add links
dictSwitches[curSwitch].add_link(tgen.gears[destRouter], \
topo['switches'][curSwitch]['links'][destRouter]['interface'],
topo['routers'][destRouter]['links'][curSwitch]['interface'],
)
# IPv4
if 'ipv4' in topo['routers'][destRouter]['links'][curSwitch]:
if topo['routers'][destRouter]['links'][curSwitch]['ipv4'] == 'auto':
topo['routers'][destRouter]['links'][curSwitch]['ipv4'] = \
'{}/{}'.format(ipv4Next, topo['link_ip_start'][ \
'v4mask'])
ipv4Next += 1
# IPv6
if 'ipv6' in topo['routers'][destRouter]['links'][curSwitch]:
if topo['routers'][destRouter]['links'][curSwitch]['ipv6'] == 'auto':
topo['routers'][destRouter]['links'][curSwitch]['ipv6'] = \
'{}/{}'.format(ipv6Next, topo['link_ip_start'][ \
'v6mask'])
ipv6Next = ipaddr.IPv6Address(int(ipv6Next) + ipv6Step)
logger.debug(
"Generated link data for router: %s\n%s",
curRouter,
json_dumps(
topo["routers"][curRouter]["links"], indent=4, sort_keys=True
),
)
def build_config_from_json(tgen, topo, save_bkup=True):
"""
@ -210,6 +294,7 @@ def build_config_from_json(tgen, topo, save_bkup=True):
("bgp_community_list", create_bgp_community_lists),
("route_maps", create_route_maps),
("bgp", create_router_bgp),
("ospf", create_router_ospf)
]
)

View File

@ -0,0 +1,166 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"routers": {
"r0": {
"links": {
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r2": {},
"r3": {}
},
"redistribute": [
{
"redist_type": "static"
},
{
"redist_type": "connected"
}
]
}
},
"r1": {
"links": {
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.2",
"neighbors": {
"r1": {},
"r0": {},
"r3": {}
}
}
},
"r3": {
"links": {
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"neighbors": {
"r0": {},
"r1": {},
"r2": {}
}
}
}
}
}

View File

@ -0,0 +1,342 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"routers": {
"r0": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link4": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link5": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link6": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link7": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r1-link1": {
"nbr": "r1"
},
"r1-link2": {
"nbr": "r1"
},
"r1-link3": {
"nbr": "r1"
},
"r1-link4": {
"nbr": "r1"
},
"r1-link5": {
"nbr": "r1"
},
"r1-link6": {
"nbr": "r1"
},
"r1-link7": {
"nbr": "r1"
},
"r2": {},
"r3": {}
}
}
},
"r1": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r0-link1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r0-link2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r0-link3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r0-link4": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r0-link5": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r0-link6": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r0-link7": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3-link0": {
"ipv4": "auto",
"description": "DummyIntftoR3"
}
},
"ospf": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r0-link1": {
"nbr": "r0"
},
"r0-link2": {
"nbr": "r0"
},
"r0-link3": {
"nbr": "r0"
},
"r0-link4": {
"nbr": "r0"
},
"r0-link5": {
"nbr": "r0"
},
"r0-link6": {
"nbr": "r0"
},
"r0-link7": {
"nbr": "r0"
},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.2",
"neighbors": {
"r1": {},
"r0": {},
"r3": {}
}
}
},
"r3": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link0": {
"ipv4": "auto",
"description": "DummyIntftoR1",
"ospf": {
"area": "0.0.0.0"
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"neighbors": {
"r0": {},
"r1": {},
"r2": {}
}
}
}
}
}

View File

@ -0,0 +1,234 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"switches": {
"s1": {
"links": {
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 98
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 99
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 0
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 0
}
},
"r4": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 0
}
},
"r5": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 0
}
},
"r6": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 0
}
},
"r7": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 0
}
}
}
}
},
"routers": {
"r0": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r2": {},
"r3": {}
}
}
},
"r1": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r3-link0": {
"ipv4": "auto",
"description": "DummyIntftoR3"
}
},
"ospf": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
}
},
"ospf": {
"router_id": "100.1.1.2",
"area": [{
"id": "0.0.0.2",
"type": "nssa"
}],
"neighbors": {
"r1": {},
"r0": {}
}
}
},
"r3": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r1-link0": {
"ipv4": "auto",
"description": "DummyIntftoR1",
"ospf": {
"area": "0.0.0.3"
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"area": [{
"id": "0.0.0.2",
"type": "nssa"
}],
"neighbors": {
"r0": {},
"r1": {}
}
}
},
"r4": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
}
},
"ospf": {
"router_id": "100.1.1.4",
"neighbors": {
"r0": {},
"r1": {}
}
}
},
"r5": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
}
},
"ospf": {
"router_id": "100.1.1.5",
"neighbors": {
"r0": {},
"r1": {}
}
}
},
"r6": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
}
},
"ospf": {
"router_id": "100.1.1.6",
"neighbors": {
"r0": {},
"r1": {}
}
}
},
"r7": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
}
},
"ospf": {
"router_id": "100.1.1.7",
"neighbors": {
"r0": {},
"r1": {}
}
}
}
}
}

View File

@ -0,0 +1,138 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"switches": {
"s1": {
"links": {
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 98
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 99
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 0
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.3",
"hello_interval": 1,
"dead_interval": 4,
"priority": 0
}
}
}
}
},
"routers": {
"r0": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r2": {},
"r3": {}
}
}
},
"r1": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r3-link0": {
"ipv4": "auto",
"description": "DummyIntftoR3"
}
},
"ospf": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
}
},
"ospf": {
"router_id": "100.1.1.2",
"area": [{
"id": "0.0.0.2",
"type": "nssa"
}],
"neighbors": {
"r1": {},
"r0": {}
}
}
},
"r3": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r1-link0": {
"ipv4": "auto",
"description": "DummyIntftoR1",
"ospf": {
"area": "0.0.0.3"
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"area": [{
"id": "0.0.0.2",
"type": "nssa"
}],
"neighbors": {
"r0": {},
"r1": {}
}
}
}
}
}

View File

@ -0,0 +1,188 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"routers": {
"r0": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto"
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r3": {}
}
}
},
"r1": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.2",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.2",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3-link0": {
"ipv4": "auto",
"description": "DummyIntftoR3"
}
},
"ospf": {
"router_id": "100.1.1.1",
"area": [{
"id": "0.0.0.2",
"type": "nssa"
}],
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto"
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.2",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.2",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.2",
"area": [{
"id": "0.0.0.2",
"type": "nssa"
}],
"neighbors": {
"r1": {},
"r3": {}
}
}
},
"r3": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.2",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.2",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link0": {
"ipv4": "auto",
"description": "DummyIntftoR1",
"ospf": {
"area": "0.0.0.3"
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"area": [{
"id": "0.0.0.2",
"type": "nssa"
}],
"neighbors": {
"r0": {},
"r1": {},
"r2": {}
}
}
}
}
}

View File

@ -0,0 +1,159 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"routers": {
"r0": {
"links": {
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r2": {},
"r3": {}
}
}
},
"r1": {
"links": {
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.2",
"neighbors": {
"r1": {},
"r0": {},
"r3": {}
}
}
},
"r3": {
"links": {
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"neighbors": {
"r0": {},
"r1": {},
"r2": {}
}
}
}
}
}

View File

@ -0,0 +1,168 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"routers": {
"r0": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r2": {}
}
}
},
"r1": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.2",
"neighbors": {
"r1": {},
"r0": {},
"r3": {}
}
}
},
"r3": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto"
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"neighbors": {
"r1": {},
"r2": {}
}
}
}
}
}

View File

@ -0,0 +1,188 @@
{
"ipv4base": "10.0.0.0",
"ipv4mask": 24,
"link_ip_start": {
"ipv4": "10.0.0.0",
"v4mask": 24
},
"lo_prefix": {
"ipv4": "1.0.",
"v4mask": 32
},
"routers": {
"r0": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
}
},
"ospf": {
"router_id": "100.1.1.0",
"neighbors": {
"r1": {},
"r2": {},
"r3": {}
}
}
},
"r1": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3-link0": {
"ipv4": "auto",
"description": "DummyIntftoR3"
}
},
"ospf": {
"router_id": "100.1.1.1",
"neighbors": {
"r0": {},
"r2": {},
"r3": {}
}
}
},
"r2": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r3": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
}
},
"ospf": {
"router_id": "100.1.1.2",
"neighbors": {
"r1": {},
"r0": {},
"r3": {}
}
}
},
"r3": {
"links": {
"lo": {
"ipv4": "auto",
"type": "loopback"
},
"r0": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4,
"network": "point-to-point"
}
},
"r1": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r2": {
"ipv4": "auto",
"ospf": {
"area": "0.0.0.0",
"hello_interval": 1,
"dead_interval": 4
}
},
"r1-link0": {
"ipv4": "auto",
"description": "DummyIntftoR1",
"ospf": {
"area": "0.0.0.0"
}
}
},
"ospf": {
"router_id": "100.1.1.3",
"neighbors": {
"r0": {},
"r1": {},
"r2": {}
}
}
}
}
}

View File

@ -0,0 +1,891 @@
#!/usr/bin/python
#
# Copyright (c) 2020 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
# ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""OSPF Basic Functionality Automation."""
import os
import sys
import time
import pytest
from time import sleep
from copy import deepcopy
import json
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from mininet.topo import Topo
from lib.topogen import Topogen, get_topogen
# Import topoJson from lib, to create topology and initial configuration
from lib.common_config import (
start_topology,
write_test_header,
write_test_footer,
reset_config_on_routers,
step,
shutdown_bringup_interface,
topo_daemons
)
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.ospf import verify_ospf_neighbor, config_ospf_interface, clear_ospf
from ipaddress import IPv4Address
# Global variables
topo = None
# Reading the data from JSON File for topology creation
jsonFile = "{}/ospf_authentication.json".format(CWD)
try:
with open(jsonFile, "r") as topoJson:
topo = json.load(topoJson)
except IOError:
assert False, "Could not read file {}".format(jsonFile)
"""
TOPOOLOGY =
Please view in a fixed-width font such as Courier.
+---+ A1 +---+
+R1 +------------+R2 |
+-+-+- +--++
| -- -- |
| -- A0 -- |
A0| ---- |
| ---- | A2
| -- -- |
| -- -- |
+-+-+- +-+-+
+R0 +-------------+R3 |
+---+ A3 +---+
TESTCASES =
1. Verify ospf authentication with Simple password authentication.
2. Verify ospf authentication with MD5 authentication.
3. Verify ospf authentication with different authentication methods.
"""
class CreateTopo(Topo):
"""
Test topology builder.
* `Topo`: Topology object
"""
def build(self, *_args, **_opts):
"""Build function."""
tgen = get_topogen(self)
# Building topology from json file
build_topo_from_json(tgen, topo)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
global topo
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, topo)
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen, daemons)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
logger.info("Running setup_module() done")
def teardown_module(mod):
"""
Teardown the pytest environment.
* `mod`: module name
"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info(
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
# ##################################
# Test cases start here.
# ##################################
def test_ospf_authentication_simple_pass_tc28_p1(request):
"""
OSPF Authentication - Verify ospf authentication with Simple
password authentication.
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
global topo
step("Bring up the base config.")
reset_config_on_routers(tgen)
step(
"Configure ospf with on R1 and R2, enable ospf on R1 interface"
"connected to R2 with simple password authentication using ip ospf "
"authentication Simple password cmd."
)
r1_ospf_auth = {
"r1": {
"links": {
"r2": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("clear ip ospf after configuring the authentication.")
clear_ospf(tgen, "r1")
step("Verify that the neighbour is not FULL between R1 and R2.")
dut = "r1"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(
"On R2 enable ospf on interface with simple password authentication "
"using ip ospf authentication Simple password cmd."
)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the neighbour is FULL between R1 and R2 "
"using show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(
"Disable simple password authentication on R2 using no ip ospf "
"authentication Simple password cmd."
)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": True,
"authentication-key": "ospf",
"del_action": True,
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Verify on R1 neighbour is deleted for R2 after dead interval expiry")
# wait till the dead time expiry
sleep(6)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(
tgen, topo, dut=dut, expected=False, attempts=5
)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Again On R2 enable ospf on interface with Simple password auth")
r2_ospf_auth = {
"r2": {
"links": {
"r1": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the neighbour is FULL between R1 and R2 using"
" show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Shut no shut interface on R1")
dut = "r1"
intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
dut = "r2"
step(
"Verify that the neighbour is not FULL between R1 and R2 using "
"show ip ospf neighbor cmd."
)
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
dut = "r1"
shutdown_bringup_interface(tgen, dut, intf, True)
step(
"Verify that the neighbour is FULL between R1 and R2 using "
"show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Change Ip address on R1 and R2")
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
IPv4Address(unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
reset_config_on_routers(tgen, routerName="r1")
dut = "r1"
intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
shutdown_bringup_interface(tgen, dut, intf, True)
# clear ip ospf after configuring the authentication.
clear_ospf(tgen, "r1")
r1_ospf_auth = {
"r1": {
"links": {
"r2": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the neighbour is FULL between R1 and R2 with new "
"ip address using show ip ospf "
)
dut = "r1"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
write_test_footer(tc_name)
def test_ospf_authentication_md5_tc29_p1(request):
"""
OSPF Authentication - Verify ospf authentication with MD5 authentication.
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
global topo
step("Bring up the base config.")
reset_config_on_routers(tgen)
step(
"Configure ospf with on R1 and R2, enable ospf on R1 interface "
"connected to R2 with message-digest authentication using ip "
"ospf authentication message-digest cmd."
)
r1_ospf_auth = {
"r1": {
"links": {
"r2": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Verify that the neighbour is not FULL between R1 and R2.")
# wait for dead time expiry.
sleep(6)
dut = "r1"
ospf_covergence = verify_ospf_neighbor(
tgen, topo, dut=dut, expected=False, attempts=3
)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(
"On R2 enable ospf on interface with message-digest authentication"
" using ip ospf authentication message-digest password cmd."
)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the neighbour is FULL between R1 and R2 "
"using show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(
"Disable message-digest authentication on R2 using no ip ospf "
"authentication message-digest password cmd."
)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
"del_action": True,
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Verify on R1 ,nbr is deleted for R2 after dead interval expiry")
# wait till the dead timer expiry
sleep(6)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(
tgen, topo, dut=dut, expected=False, attempts=5
)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Again On R2 enable ospf on interface with message-digest auth")
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the neighbour is FULL between R1 and R2 using"
" show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Shut no shut interface on R1")
dut = "r1"
intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
dut = "r2"
step(
"Verify that the neighbour is not FULL between R1 and R2 using "
"show ip ospf neighbor cmd."
)
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, expected=False)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
dut = "r1"
shutdown_bringup_interface(tgen, dut, intf, True)
step(
"Verify that the neighbour is FULL between R1 and R2 using "
"show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Change Ip address on R1 and R2")
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"]
topo_modify_change_ip["routers"]["r1"]["links"]["r2"]["ipv4"] = str(
IPv4Address(unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
reset_config_on_routers(tgen, routerName="r1")
dut = "r1"
intf = topo["routers"]["r1"]["links"]["r2"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
shutdown_bringup_interface(tgen, dut, intf, True)
clear_ospf(tgen, "r1")
r1_ospf_auth = {
"r1": {
"links": {
"r2": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the neighbour is FULL between R1 and R2 with new "
"ip address using show ip ospf "
)
dut = "r1"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
write_test_footer(tc_name)
def test_ospf_authentication_different_auths_tc30_p1(request):
"""
OSPF Authentication - Verify ospf authentication with different
authentication methods.
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
global topo
step("Bring up the base config.")
reset_config_on_routers(tgen)
step(
"Configure ospf with on R1 and R2, enable ospf on R1 interface "
"connected to R2 with message-digest authentication using ip "
"ospf authentication message-digest cmd."
)
r1_ospf_auth = {
"r1": {
"links": {
"r2": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
# wait for dead timer expiry
sleep(6)
step("Verify that the neighbour is not FULL between R1 and R2.")
dut = "r1"
ospf_covergence = verify_ospf_neighbor(
tgen, topo, dut=dut, expected=False, attempts=5
)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(
"On R2 enable ospf on interface with message-digest authentication"
" using ip ospf authentication message-digest password cmd."
)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the neighbour is FULL between R1 and R2 "
"using show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(" Delete the configured password on both the routers.")
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
"del_action": True,
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
r1_ospf_auth = {
"r1": {
"links": {
"r2": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
"del_action": True,
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the deletion is successful and neighbour is FULL"
" between R1 and R2 using show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Change the authentication type to simple password.")
r1_ospf_auth = {
"r1": {
"links": {
"r2": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {"ospf": {"authentication": True, "authentication-key": "ospf"}}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the deletion is successful and neighbour is"
" FULL between R1 and R2 using show ip "
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Change the password in simple password.")
r1_ospf_auth = {
"r1": {
"links": {
"r2": {"ospf": {"authentication": True, "authentication-key": "OSPFv4"}}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {"ospf": {"authentication": True, "authentication-key": "OSPFv4"}}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the deletion is successful and neighbour is"
" FULL between R1 and R2 using show ip "
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Delete the password authentication on the interface ")
r1_ospf_auth = {
"r1": {
"links": {
"r2": {
"ospf": {
"authentication": True,
"authentication-key": "OSPFv4",
"del_action": True,
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": True,
"authentication-key": "OSPFv4",
"del_action": True,
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the deletion is successful and neighbour is"
" FULL between R1 and R2 using show ip "
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Enable Md5 authentication on the interface")
r1_ospf_auth = {
"r1": {
"links": {
"r2": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "ospf",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Verify that the neighbour is FULL between R1 and R2 using"
" show ip ospf neighbor cmd."
)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Change the MD5 authentication password")
r1_ospf_auth = {
"r1": {
"links": {
"r2": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "OSPFv4",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r1_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
r2_ospf_auth = {
"r2": {
"links": {
"r1": {
"ospf": {
"authentication": "message-digest",
"authentication-key": "OSPFv4",
"message-digest-key": "10",
}
}
}
}
}
result = config_ospf_interface(tgen, topo, r2_ospf_auth)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,495 @@
#!/usr/bin/python
#
# Copyright (c) 2020 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
# ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""OSPF Basic Functionality Automation."""
import os
import sys
import time
import pytest
import json
from time import sleep
from copy import deepcopy
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from mininet.topo import Topo
from lib.topogen import Topogen, get_topogen
from ipaddress import IPv4Address
# Import topoJson from lib, to create topology and initial configuration
from lib.common_config import (
start_topology,
write_test_header,
write_test_footer,
reset_config_on_routers,
verify_rib,
create_static_routes,
step,
create_route_maps,
shutdown_bringup_interface,
create_interfaces_cfg,
topo_daemons
)
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.ospf import (
verify_ospf_neighbor,
config_ospf_interface,
clear_ospf,
verify_ospf_rib,
create_router_ospf,
verify_ospf_interface,
)
topo = None
# Reading the data from JSON File for topology creation
jsonFile = "{}/ospf_ecmp.json".format(CWD)
try:
with open(jsonFile, "r") as topoJson:
topo = json.load(topoJson)
except IOError:
assert False, "Could not read file {}".format(jsonFile)
# Global variables
NETWORK = {
"ipv4": [
"11.0.20.1/32",
"11.0.20.2/32",
"11.0.20.3/32",
"11.0.20.4/32",
"11.0.20.5/32",
]
}
"""
TOPOLOGY :
Please view in a fixed-width font such as Courier.
+---+ A1 +---+
+R1 +------------+R2 |
+-+-+- +--++
| -- -- |
| -- A0 -- |
A0| ---- |
| ---- | A2
| -- -- |
| -- -- |
+-+-+- +-+-+
+R0 +-------------+R3 |
+---+ A3 +---+
TESTCASES :
1. Verify OSPF ECMP with max path configured as 8 (ECMPconfigured at FRR level)
2. Verify OSPF ECMP with max path configured as 2 (Edge having 2 uplink ports)
"""
class CreateTopo(Topo):
"""
Test topology builder.
* `Topo`: Topology object
"""
def build(self, *_args, **_opts):
"""Build function."""
tgen = get_topogen(self)
# Building topology from json file
build_topo_from_json(tgen, topo)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
global topo
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, topo)
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen, daemons)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Api call verify whether OSPF is converged
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
logger.info("Running setup_module() done")
def teardown_module(mod):
"""
Teardown the pytest environment.
* `mod`: module name
"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info(
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
def red_static(dut, config=True):
"""Local def for Redstribute static routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
else:
ospf_red = {
dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase : Failed \n Error: {}".format(result)
def red_connected(dut, config=True):
"""Local def for Redstribute connected routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
else:
ospf_red = {
dut: {
"ospf": {
"redistribute": [{"redist_type": "connected", "del_action": True}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase: Failed \n Error: {}".format(result)
# ##################################
# Test cases start here.
# ##################################
def test_ospf_ecmp_tc16_p0(request):
"""
Verify OSPF ECMP.
Verify OSPF ECMP with max path configured as 8 (ECMP
configured at FRR level)
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config as per the topology")
step("Configure 8 interfaces between R1 and R2 and enable ospf in area 0.")
reset_config_on_routers(tgen)
step("Verify that OSPF is up with 8 neighborship sessions.")
dut = "r1"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Configure a static route in R0 and redistribute in OSPF.")
input_dict = {
"r0": {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
dut = "r0"
red_static(dut)
step("Verify that route in R2 in stalled with 8 next hops.")
nh = []
for item in range(1, 7):
nh.append(topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0])
nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
nh.append(nh2)
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("shut no shut all the interfaces on the remote router - R2")
dut = "r1"
for intfr in range(1, 7):
intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
protocol = "ospf"
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
for intfr in range(1, 7):
intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"]
shutdown_bringup_interface(tgen, dut, intf, True)
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("shut no shut on all the interfaces on DUT (r1)")
for intfr in range(1, 7):
intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
for intfr in range(1, 7):
intf = topo["routers"]["r1"]["links"]["r0-link{}".format(intfr)]["interface"]
shutdown_bringup_interface(tgen, dut, intf, True)
step(
"Verify that all the neighbours are up and routes are installed"
" with 8 next hop in ospf and ip route tables on R1."
)
step("Verify that OSPF is up with 8 neighborship sessions.")
dut = "r1"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(" Un configure static route on R0")
dut = "r0"
red_static(dut, config=False)
# Wait for R0 to flush external LSAs.
sleep(10)
step("Verify that route is withdrawn from R2.")
dut = "r1"
result = verify_ospf_rib(
tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
protocol = "ospf"
result = verify_rib(
tgen,
"ipv4",
dut,
input_dict,
protocol=protocol,
next_hop=nh,
attempts=5,
expected=False,
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Re configure the static route in R0.")
dut = "r0"
red_static(dut)
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
def test_ospf_ecmp_tc17_p0(request):
"""
Verify OSPF ECMP.
Verify OSPF ECMP with max path configured as 2 (Edge having 2 uplink ports)
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config as per the topology")
step("Configure 2 interfaces between R1 and R2 & enable ospf in area 0.")
reset_config_on_routers(tgen)
step("Verify that OSPF is up with 2 neighborship sessions.")
dut = "r1"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Configure a static route in R0 and redistribute in OSPF.")
input_dict = {
"r0": {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
dut = "r0"
red_static(dut)
step("Verify that route in R2 in stalled with 2 next hops.")
nh1 = topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0]
nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
nh = [nh1, nh2]
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(" Un configure static route on R0")
dut = "r0"
red_static(dut, config=False)
# sleep till the route gets withdrawn
sleep(10)
step("Verify that route is withdrawn from R2.")
dut = "r1"
result = verify_ospf_rib(
tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
protocol = "ospf"
result = verify_rib(
tgen,
"ipv4",
dut,
input_dict,
protocol=protocol,
next_hop=nh,
attempts=5,
expected=False,
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Reconfigure the static route in R0.Change ECMP value to 2.")
dut = "r0"
red_static(dut)
step("Configure cost on R0 as 100")
r0_ospf_cost = {"r0": {"links": {"r1": {"ospf": {"cost": 100}}}}}
result = config_ospf_interface(tgen, topo, r0_ospf_cost)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,369 @@
#!/usr/bin/python
#
# Copyright (c) 2020 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
# ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""OSPF Basic Functionality Automation."""
import os
import sys
import time
import pytest
import json
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from mininet.topo import Topo
from lib.topogen import Topogen, get_topogen
# Import topoJson from lib, to create topology and initial configuration
from lib.common_config import (
start_topology,
write_test_header,
create_interfaces_cfg,
write_test_footer,
reset_config_on_routers,
verify_rib,
create_static_routes,
check_address_types,
step,
create_route_maps,
shutdown_bringup_interface,
stop_router,
start_router,
topo_daemons
)
from lib.bgp import verify_bgp_convergence, create_router_bgp
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.ospf import (
verify_ospf_neighbor,
config_ospf_interface,
clear_ospf,
verify_ospf_rib,
create_router_ospf,
verify_ospf_interface,
)
from ipaddress import IPv4Address
# Global variables
topo = None
# Reading the data from JSON File for topology creation
jsonFile = "{}/ospf_ecmp_lan.json".format(CWD)
try:
with open(jsonFile, "r") as topoJson:
topo = json.load(topoJson)
except IOError:
assert False, "Could not read file {}".format(jsonFile)
NETWORK = {
"ipv4": [
"11.0.20.1/32",
"11.0.20.2/32",
"11.0.20.3/32",
"11.0.20.4/32",
"11.0.20.5/32",
],
"ipv6": ["1::1/128", "1::2/128", "1::3/128", "1::4/128", "1::5/128"],
}
MASK = {"ipv4": "32", "ipv6": "128"}
NEXT_HOP = {
"ipv4": ["10.0.0.1", "10.0.1.1", "10.0.2.1", "10.0.3.1", "10.0.4.1"],
"ipv6": ["Null0", "Null0", "Null0", "Null0", "Null0"],
}
"""
TOPOOLOGY =
Please view in a fixed-width font such as Courier.
Topo : Broadcast Networks
+---+ +---+ +---+ +---+
|R0 + +R1 + +R2 + +R3 |
+-+-+ +-+-+ +-+-+ +-+-+
| | | |
| | | |
--+-----------+--------------+---------------+-----
Ethernet Segment
TESTCASES =
1. Verify OSPF ECMP with max path configured as 8
(Edge having 1 uplink port as broadcast network,
connect to 8 TORs - LAN case)
"""
class CreateTopo(Topo):
"""
Test topology builder.
* `Topo`: Topology object
"""
def build(self, *_args, **_opts):
"""Build function."""
tgen = get_topogen(self)
# Building topology from json file
build_topo_from_json(tgen, topo)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
global topo
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, topo)
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen, daemons)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Api call verify whether OSPF is converged
ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
logger.info("Running setup_module() done")
def teardown_module():
"""Teardown the pytest environment"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
try:
# Stop toplogy and Remove tmp files
tgen.stop_topology()
except OSError:
# OSError exception is raised when mininet tries to stop switch
# though switch is stopped once but mininet tries to stop same
# switch again, where it ended up with exception
pass
def red_static(dut, config=True):
"""Local def for Redstribute static routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
else:
ospf_red = {
dut: {
"ospf": {
"redistribute": [{"redist_type": "static", "del_action": True}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase : Failed \n Error: {}".format(result)
def red_connected(dut, config=True):
"""Local def for Redstribute connected routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
else:
ospf_red = {
dut: {
"ospf": {
"redistribute": [{"redist_type": "connected", "del_action": True}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase: Failed \n Error: {}".format(result)
# ##################################
# Test cases start here.
# ##################################
def test_ospf_lan_ecmp_tc18_p0(request):
"""
OSPF ECMP.
Verify OSPF ECMP with max path configured as 8
(Edge having 1 uplink port as broadcast network,
connect to 8 TORs - LAN case)
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config as per the topology")
step(". Configure ospf in all the routers on LAN interface.")
reset_config_on_routers(tgen)
step("Verify that OSPF is up with 8 neighborship sessions.")
ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(
"Configure a static route in all the routes and "
"redistribute static/connected in OSPF."
)
for rtr in topo["routers"]:
input_dict = {
rtr: {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0"}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
dut = rtr
red_static(dut)
step(
"Verify that route in R0 in stalled with 8 hops. "
"Verify ospf route table and ip route table."
)
nh = []
for rtr in topo["routers"]:
nh.append(topo["routers"][rtr]["links"]["s1"]["ipv4"].split("/")[0])
nh.remove(topo["routers"]["r1"]["links"]["s1"]["ipv4"].split("/")[0])
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(" clear ip ospf interface on DUT(r0)")
clear_ospf(tgen, "r0")
step(
"Verify that after clearing the ospf interface all the "
"neighbours are up and routes are installed with 8 next hop "
"in ospf and ip route tables on R0"
)
dut = "r0"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, lan=True)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(" clear ip ospf interface on R2")
clear_ospf(tgen, "r2")
dut = "r2"
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut, lan=True)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Delete static/connected cmd in ospf in all the routes one by one.")
for rtr in topo["routers"]:
input_dict = {
rtr: {
"static_routes": [
{
"network": NETWORK["ipv4"][0],
"no_of_ip": 5,
"next_hop": "Null0",
"delete": True,
}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Verify that all the routes are withdrawn from R0")
dut = "r1"
result = verify_ospf_rib(
tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
protocol = "ospf"
result = verify_rib(
tgen,
"ipv4",
dut,
input_dict,
protocol=protocol,
next_hop=nh,
attempts=5,
expected=False,
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,724 @@
#!/usr/bin/python
#
# Copyright (c) 2020 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
# ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""OSPF Basic Functionality Automation."""
import os
import sys
import time
import pytest
import json
from copy import deepcopy
import ipaddress
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from mininet.topo import Topo
from lib.topogen import Topogen, get_topogen
# Import topoJson from lib, to create topology and initial configuration
from lib.common_config import (
start_topology,
write_test_header,
create_interfaces_cfg,
write_test_footer,
reset_config_on_routers,
verify_rib,
create_static_routes,
check_address_types,
step,
create_route_maps,
shutdown_bringup_interface,
stop_router,
start_router,
topo_daemons
)
from lib.bgp import verify_bgp_convergence, create_router_bgp
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.ospf import (
verify_ospf_neighbor,
config_ospf_interface,
clear_ospf,
verify_ospf_rib,
create_router_ospf,
verify_ospf_interface,
)
from ipaddress import IPv4Address
# Global variables
topo = None
# Reading the data from JSON File for topology creation
jsonFile = "{}/ospf_lan.json".format(CWD)
try:
with open(jsonFile, "r") as topoJson:
topo = json.load(topoJson)
except IOError:
assert False, "Could not read file {}".format(jsonFile)
NETWORK = {
"ipv4": [
"11.0.20.1/32",
"11.0.20.2/32",
"11.0.20.3/32",
"11.0.20.4/32",
"11.0.20.5/32",
]
}
"""
Topology:
Please view in a fixed-width font such as Courier.
Topo : Broadcast Networks
+---+ +---+ +---+ +---+
|R0 + +R1 + +R2 + +R3 |
+-+-+ +-+-+ +-+-+ +-+-+
| | | |
| | | |
--+-----------+--------------+---------------+-----
Ethernet Segment
Testcases:
1. OSPF Hello protocol - Verify DR BDR Elections
2. OSPF IFSM -Verify state change events on DR / BDR / DR Other
"""
class CreateTopo(Topo):
"""
Test topology builder.
* `Topo`: Topology object
"""
def build(self, *_args, **_opts):
"""Build function."""
tgen = get_topogen(self)
# Building topology from json file
build_topo_from_json(tgen, topo)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
global topo
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, topo)
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen, daemons)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Api call verify whether OSPF is converged
ospf_covergence = verify_ospf_neighbor(tgen, topo, lan=True)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
logger.info("Running setup_module() done")
def teardown_module():
"""Teardown the pytest environment"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
try:
# Stop toplogy and Remove tmp files
tgen.stop_topology
except OSError:
# OSError exception is raised when mininet tries to stop switch
# though switch is stopped once but mininet tries to stop same
# switch again, where it ended up with exception
pass
def red_static(dut, config=True):
"""Local def for Redstribute static routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
else:
ospf_red = {
dut: {
"ospf": {
"redistribute": [{"redist_type": "static", "del_action": True}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase : Failed \n Error: {}".format(result)
def red_connected(dut, config=True):
"""Local def for Redstribute connected routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
else:
ospf_red = {
dut: {
"ospf": {
"redistribute": [{"redist_type": "connected", "del_action": True}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase: Failed \n Error: {}".format(result)
# ##################################
# Test cases start here.
# ##################################
def test_ospf_lan_tc1_p0(request):
"""
OSPF Hello protocol - Verify DR BDR Elections
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config as per the topology")
reset_config_on_routers(tgen)
step("Verify that DR BDR DRother are elected in the LAN.")
input_dict = {
"r0": {
"ospf": {
"neighbors": {
"r1": {"state": "Full", "role": "DR"},
"r2": {"state": "Full", "role": "DROther"},
"r3": {"state": "Full", "role": "DROther"},
}
}
}
}
dut = "r0"
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Verify that all the routers are in FULL state with DR and BDR "
"in the topology"
)
input_dict = {
"r1": {
"ospf": {
"neighbors": {
"r0": {"state": "Full", "role": "Backup"},
"r2": {"state": "Full", "role": "DROther"},
"r3": {"state": "Full", "role": "DROther"},
}
}
}
}
dut = "r1"
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Configure DR pririty 100 on R0 and clear ospf neighbors " "on all the routers."
)
input_dict = {
"r0": {
"links": {
"s1": {
"interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
"ospf": {"priority": 100},
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Clear ospf neighbours in all routers")
for rtr in ["r0", "r1", "r2", "r3"]:
clear_ospf(tgen, rtr)
step("Verify that DR election is triggered and R0 is elected as DR")
input_dict = {
"r0": {
"ospf": {
"neighbors": {
"r1": {"state": "Full", "role": "Backup"},
"r2": {"state": "Full", "role": "DROther"},
"r3": {"state": "Full", "role": "DROther"},
}
}
}
}
dut = "r0"
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Configure DR pririty 150 on R0 and clear ospf neighbors " "on all the routers."
)
input_dict = {
"r0": {
"links": {
"s1": {
"interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
"ospf": {"priority": 150},
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Clear ospf neighbours in all routers")
for rtr in ["r0", "r1"]:
clear_ospf(tgen, rtr)
step("Verify that DR election is triggered and R0 is elected as DR")
input_dict = {
"r0": {
"ospf": {
"neighbors": {
"r1": {"state": "Full", "role": "Backup"},
"r2": {"state": "Full", "role": "DROther"},
"r3": {"state": "Full", "role": "DROther"},
}
}
}
}
dut = "r0"
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Configure DR priority 0 on R0 & Clear ospf nbrs on all the routers")
input_dict = {
"r0": {
"links": {
"s1": {
"interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
"ospf": {"priority": 0},
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Clear ospf neighbours in all routers")
for rtr in ["r1"]:
clear_ospf(tgen, rtr)
step("Verify that DR election is triggered and R0 is elected as DRother")
input_dict = {
"r0": {
"ospf": {
"neighbors": {
"r1": {"state": "Full", "role": "DR"},
"r2": {"state": "2-Way", "role": "DROther"},
"r3": {"state": "2-Way", "role": "DROther"},
}
}
}
}
dut = "r0"
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Configure DR priority to default on R0 and Clear ospf neighbors"
" on all the routers"
)
input_dict = {
"r0": {
"links": {
"s1": {
"interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
"ospf": {"priority": 100},
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Clear ospf neighbours in all routers")
for rtr in ["r0", "r1"]:
clear_ospf(tgen, rtr)
step("Verify that DR election is triggered and R0 is elected as DR")
input_dict = {
"r0": {
"ospf": {
"neighbors": {
"r1": {"state": "Full", "role": "Backup"},
"r2": {"state": "Full", "role": "DROther"},
"r3": {"state": "Full", "role": "DROther"},
}
}
}
}
dut = "r0"
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Shut interface on R0")
dut = "r0"
intf = topo["routers"]["r0"]["links"]["s1"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
result = verify_ospf_neighbor(tgen, topo, dut, lan=True, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("No Shut interface on R0")
dut = "r0"
intf = topo["routers"]["r0"]["links"]["s1"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, True)
input_dict = {
"r0": {
"ospf": {
"neighbors": {
"r1": {"state": "Full", "role": "DR"},
"r2": {"state": "Full", "role": "DROther"},
"r3": {"state": "Full", "role": "DROther"},
}
}
}
}
step("Verify that after no shut ospf neighbours are full on R0.")
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Clear ospf on DR router in the topology.")
clear_ospf(tgen, "r0")
step("Verify that BDR is getting promoted to DR after clear.")
step("Verify that all the nbrs are in FULL state with the elected DR.")
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Change the ip on LAN intf on R0 to other ip from the same subnet.")
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
IPv4Address(unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
step(
"Verify that OSPF is in FULL state with other routers with "
"newly configured IP."
)
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Change the ospf router id on the R0 and clear ip ospf interface.")
change_rid = {"r0": {"ospf": {"router_id": "100.1.1.100"}}}
result = create_router_ospf(tgen, topo, change_rid)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo["routers"]["r0"]["ospf"]["router_id"] = "100.1.1.100"
step("Reload the FRR router")
stop_router(tgen, "r0")
start_router(tgen, "r0")
step(
"Verify that OSPF is in FULL state with other routers with"
" newly configured router id."
)
input_dict = {
"r1": {
"ospf": {
"neighbors": {
"r0": {"state": "Full", "role": "Backup"},
"r2": {"state": "Full", "role": "DROther"},
"r3": {"state": "Full", "role": "DROther"},
}
}
}
}
dut = "r1"
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Reconfigure the original router id and clear ip ospf interface.")
change_rid = {"r0": {"ospf": {"router_id": "100.1.1.0"}}}
result = create_router_ospf(tgen, topo, change_rid)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo["routers"]["r0"]["ospf"]["router_id"] = "100.1.1.0"
step("Reload the FRR router")
# stop/start -> restart FRR router and verify
stop_router(tgen, "r0")
start_router(tgen, "r0")
step("Verify that OSPF is enabled with router id previously configured.")
input_dict = {
"r1": {
"ospf": {
"neighbors": {
"r0": {"state": "Full", "role": "Backup"},
"r2": {"state": "Full", "role": "DROther"},
"r3": {"state": "Full", "role": "DROther"},
}
}
}
}
dut = "r1"
result = verify_ospf_neighbor(tgen, topo, dut, input_dict, lan=True)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
def test_ospf_lan_tc2_p0(request):
"""
OSPF IFSM -Verify state change events on DR / BDR / DR Other
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config as per the topology")
reset_config_on_routers(tgen)
step(
"Verify that OSPF is subscribed to multi cast services "
"(All SPF, all DR Routers)."
)
step("Verify that interface is enabled in ospf.")
dut = "r0"
input_dict = {
"r0": {
"links": {
"s1": {
"ospf": {
"priority": 98,
"timerDeadSecs": 4,
"area": "0.0.0.3",
"mcastMemberOspfDesignatedRouters": True,
"mcastMemberOspfAllRouters": True,
"ospfEnabled": True,
}
}
}
}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Delete the ip address")
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": topo["routers"]["r0"]["links"]["s1"]["ipv4"],
"interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Change the ip on the R0 interface")
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
IPv4Address(unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
step("Verify that interface is enabled in ospf.")
dut = "r0"
input_dict = {
"r0": {
"links": {
"s1": {
"ospf": {
"ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
"s1"
]["ipv4"].split("/")[0],
"ipAddressPrefixlen": int(
topo_modify_change_ip["routers"]["r0"]["links"]["s1"][
"ipv4"
].split("/")[1]
),
}
}
}
}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Modify the mask on the R0 interface")
ip_addr = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
mask = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
step("Delete the ip address")
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": ip_addr,
"interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Change the ip on the R0 interface")
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str(
IPv4Address(unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
step("Verify that interface is enabled in ospf.")
dut = "r0"
input_dict = {
"r0": {
"links": {
"s1": {
"ospf": {
"ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
"s1"
]["ipv4"].split("/")[0],
"ipAddressPrefixlen": int(
topo_modify_change_ip["routers"]["r0"]["links"]["s1"][
"ipv4"
].split("/")[1]
),
}
}
}
}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Change the area id on the interface")
input_dict = {
"r0": {
"links": {
"s1": {
"interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
"ospf": {"area": "0.0.0.3"},
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
input_dict = {
"r0": {
"links": {
"s1": {
"interface": topo["routers"]["r0"]["links"]["s1"]["interface"],
"ospf": {"area": "0.0.0.2"},
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Verify that interface is enabled in ospf.")
dut = "r0"
input_dict = {
"r0": {"links": {"s1": {"ospf": {"area": "0.0.0.2", "ospfEnabled": True}}}}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,336 @@
#!/usr/bin/python
#
# Copyright (c) 2020 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
# ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""OSPF Basic Functionality Automation."""
import ipaddress
from lib.ospf import (
verify_ospf_neighbor,
config_ospf_interface,
clear_ospf,
verify_ospf_rib,
create_router_ospf,
verify_ospf_interface,
)
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.topolog import logger
from lib.common_config import (
start_topology,
write_test_header,
write_test_footer,
reset_config_on_routers,
verify_rib,
create_static_routes,
step,
create_route_maps,
shutdown_bringup_interface,
create_interfaces_cfg,
topo_daemons
)
from ipaddress import IPv4Address
from lib.topogen import Topogen, get_topogen
from mininet.topo import Topo
import os
import sys
import time
import pytest
import json
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
# Global variables
topo = None
# Reading the data from JSON File for topology creation
jsonFile = "{}/ospf_nssa.json".format(CWD)
try:
with open(jsonFile, "r") as topoJson:
topo = json.load(topoJson)
except IOError:
assert False, "Could not read file {}".format(jsonFile)
NETWORK = {
"ipv4": [
"11.0.20.1/32",
"11.0.20.2/32",
"11.0.20.3/32",
"11.0.20.4/32",
"11.0.20.5/32",
]
}
"""
TOPOOLOGY =
Please view in a fixed-width font such as Courier.
+---+ A1 +---+
+R1 +------------+R2 |
+-+-+- +--++
| -- -- |
| -- A0 -- |
A0| ---- |
| ---- | A2
| -- -- |
| -- -- |
+-+-+- +-+-+
+R0 +-------------+R3 |
+---+ A3 +---+
TESTCASES =
1. OSPF Learning - Verify OSPF can learn different types of LSA and
processes them.[Edge learning different types of LSAs]
2. Verify that ospf non back bone area can be configured as NSSA area
3. Verify that ospf NSSA area DUT is capable receiving & processing
Type7 N2 route.
"""
class CreateTopo(Topo):
"""
Test topology builder.
* `Topo`: Topology object
"""
def build(self, *_args, **_opts):
"""Build function."""
tgen = get_topogen(self)
# Building topology from json file
build_topo_from_json(tgen, topo)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
global topo
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, topo)
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen, daemons)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Api call verify whether OSPF is converged
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
logger.info("Running setup_module() done")
def teardown_module(mod):
"""
Teardown the pytest environment.
* `mod`: module name
"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info(
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
def red_static(dut, config=True):
"""Local def for Redstribute static routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
else:
ospf_red = {
dut: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase : Failed \n Error: {}".format(result)
def red_connected(dut, config=True):
"""Local def for Redstribute connected routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
else:
ospf_red = {
dut: {
"ospf": {
"redistribute": [{"redist_type": "connected", "del_action": True}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase: Failed \n Error: {}".format(result)
# ##################################
# Test cases start here.
# ##################################
def test_ospf_learning_tc15_p0(request):
"""Verify OSPF can learn different types of LSA and processes them.
OSPF Learning : Edge learning different types of LSAs.
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config as per the topology")
step("Configure area 1 as NSSA Area")
reset_config_on_routers(tgen)
step("Verify that Type 3 summary LSA is originated for the same Area 0")
ip = topo["routers"]["r1"]["links"]["r3-link0"]["ipv4"]
ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
dut = "r0"
input_dict = {
"r1": {
"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N IA"}]
}
}
dut = "r0"
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
input_dict = {
"r2": {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0"}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Redistribute static route in R2 ospf.")
dut = "r2"
red_static(dut)
step("Verify that Type 5 LSA is originated by R2.")
dut = "r0"
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that R0 receives Type 4 summary LSA.")
dut = "r0"
input_dict = {
"r1": {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 1, "routeType": "N E2"}
]
}
}
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Change area 1 as non nssa area (on the fly changing area" " type on DUT).")
for rtr in ["r1", "r2", "r3"]:
input_dict = {
rtr: {"ospf": {"area": [{"id": "0.0.0.2", "type": "nssa", "delete": True}]}}
}
result = create_router_ospf(tgen, topo, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Verify that OSPF neighbours are reset after changing area type.")
step("Verify that ABR R2 originates type 5 LSA in area 1.")
step("Verify that route is calculated and installed in R1.")
input_dict = {
"r1": {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 1, "routeType": "N E2"}
]
}
}
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,540 @@
#!/usr/bin/python
#
# Copyright (c) 2020 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
# ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""OSPF Basic Functionality Automation."""
import os
import sys
import time
import pytest
import json
from copy import deepcopy
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from mininet.topo import Topo
from lib.topogen import Topogen, get_topogen
# Import topoJson from lib, to create topology and initial configuration
from lib.common_config import (
start_topology,
write_test_header,
write_test_footer,
reset_config_on_routers,
create_prefix_lists,
verify_rib,
create_static_routes,
check_address_types,
step,
create_route_maps,
verify_prefix_lists,
topo_daemons
)
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.ospf import (
verify_ospf_neighbor,
clear_ospf,
verify_ospf_rib,
create_router_ospf,
verify_ospf_database,
)
# Global variables
topo = None
# Reading the data from JSON File for topology creation
jsonFile = "{}/ospf_routemaps.json".format(CWD)
try:
with open(jsonFile, "r") as topoJson:
topo = json.load(topoJson)
except IOError:
assert False, "Could not read file {}".format(jsonFile)
NETWORK = {
"ipv4": [
"11.0.20.1/32",
"11.0.20.2/32",
"11.0.20.3/32",
"11.0.20.4/32",
"11.0.20.5/32",
]
}
routerids = ["100.1.1.0", "100.1.1.1", "100.1.1.2", "100.1.1.3"]
"""
TOPOOLOGY =
Please view in a fixed-width font such as Courier.
+---+ A1 +---+
+R1 +------------+R2 |
+-+-+- +--++
| -- -- |
| -- A0 -- |
A0| ---- |
| ---- | A2
| -- -- |
| -- -- |
+-+-+- +-+-+
+R0 +-------------+R3 |
+---+ A3 +---+
TESTCASES =
1. OSPF Route map - Verify OSPF route map support functionality.
2. Verify OSPF route map support functionality when route map is not
configured at system level but configured in OSPF
3. Verify OSPF route map support functionality with set/match clauses
/call/continue/goto in a route-map to see if it takes immediate effect.
4. Verify OSPF route map support functionality
when route map actions are toggled.
5. Verify OSPF route map support functionality with multiple sequence
numbers in a single route-map for different match/set clauses.
6. Verify OSPF route map support functionality when we add/remove route-maps
with multiple set clauses and without any match statement.(Set only)
7. Verify OSPF route map support functionality when we
add/remove route-maps with multiple match clauses and without
any set statement.(Match only)
"""
class CreateTopo(Topo):
"""
Test topology builder.
* `Topo`: Topology object
"""
def build(self, *_args, **_opts):
"""Build function."""
tgen = get_topogen(self)
# Building topology from json file
build_topo_from_json(tgen, topo)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
global topo
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, topo)
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen, daemons)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Api call verify whether OSPF is converged
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
logger.info("Running setup_module() done")
def teardown_module(mod):
"""
Teardown the pytest environment.
* `mod`: module name
"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info(
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
# ##################################
# Test cases start here.
# ##################################
def test_ospf_routemaps_functionality_tc20_p0(request):
"""
OSPF route map support functionality.
Verify OSPF route map support functionality when route map is not
configured at system level but configured in OSPF
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
global topo
step("Bring up the base config as per the topology")
reset_config_on_routers(tgen)
step("Create static routes(10.0.20.1/32 and 10.0.20.2/32) in R0")
# Create Static routes
input_dict = {
"r0": {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Redistribute to ospf using route map ( non existent route map)")
ospf_red_r1 = {
"r0": {
"ospf": {
"redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red_r1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Verify that routes are not allowed in OSPF even tough no "
"matching routing map is configured."
)
dut = "r1"
protocol = "ospf"
result = verify_ospf_rib(tgen, dut, input_dict, attempts=2, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, attempts=2, expected=False
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step(
"configure the route map with the same name that is used "
"in the ospf with deny rule."
)
# Create route map
routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"action": "deny"}]}}}
result = create_route_maps(tgen, routemaps)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that now route map is activated & routes are denied in OSPF.")
dut = "r1"
protocol = "ospf"
result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
# Create route map
routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"action": "deny"}]}}}
result = create_route_maps(tgen, routemaps)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that now route map is activated & routes are denied in OSPF.")
dut = "r1"
protocol = "ospf"
result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Delete the route map.")
# Create route map
routemaps = {
"r0": {"route_maps": {"rmap_ipv4": [{"action": "deny", "delete": True}]}}
}
result = create_route_maps(tgen, routemaps)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Verify that routes are allowed in OSPF even tough "
"no matching routing map is configured."
)
dut = "r1"
protocol = "ospf"
result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
write_test_footer(tc_name)
def test_ospf_routemaps_functionality_tc24_p0(request):
"""
OSPF Route map - Multiple set clauses.
Verify OSPF route map support functionality when we
add/remove route-maps with multiple match clauses and without
any set statement.(Match only)
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
global topo
step("Bring up the base config as per the topology")
reset_config_on_routers(tgen)
step(
"Create static routes(10.0.20.1/32) in R1 and redistribute to "
"OSPF using route map."
)
# Create Static routes
input_dict = {
"r0": {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0",}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
ospf_red_r0 = {
"r0": {
"ospf": {
"redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red_r0)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
# Create ip prefix list
pfx_list = {
"r0": {
"prefix_lists": {
"ipv4": {
"pf_list_1_ipv4": [
{"seqid": 10, "network": "any", "action": "permit"}
]
}
}
}
}
result = create_prefix_lists(tgen, pfx_list)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that prefix-list is created in R0.")
result = verify_prefix_lists(tgen, pfx_list)
assert result is not True, (
"Testcase {} : Failed \n Prefix list not "
"present. Error: {}".format(tc_name, result)
)
# Create route map
routemaps = {
"r0": {
"route_maps": {
"rmap_ipv4": [
{
"action": "permit",
"match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
}
]
}
}
}
result = create_route_maps(tgen, routemaps)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that metric falls back to original metric for ospf routes.")
dut = "r1"
protocol = "ospf"
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Create static routes(10.0.20.1/32) in R1 and redistribute to "
"OSPF using route map."
)
# Create Static routes
input_dict = {
"r0": {
"static_routes": [
{
"network": NETWORK["ipv4"][1],
"no_of_ip": 1,
"next_hop": "Null0",
"tag": 1000,
}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
# Create ip prefix list
pfx_list = {
"r0": {
"prefix_lists": {
"ipv4": {
"pf_list_1_ipv4": [
{"seqid": 10, "network": "any", "action": "permit"}
]
}
}
}
}
result = create_prefix_lists(tgen, pfx_list)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that prefix-list is created in R0.")
result = verify_prefix_lists(tgen, pfx_list)
assert result is not True, (
"Testcase {} : Failed \n Prefix list not "
"present. Error: {}".format(tc_name, result)
)
# Create route map
routemaps = {
"r0": {
"route_maps": {
"rmap_ipv4": [{"action": "permit", "match": {"ipv4": {"tag": "1000"}}}]
}
}
}
result = create_route_maps(tgen, routemaps)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that metric falls back to original metric for ospf routes.")
dut = "r1"
protocol = "ospf"
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Delete the match clause with tag in route map")
# Create route map
routemaps = {
"r0": {
"route_maps": {
"rmap_ipv4": [
{
"action": "permit",
"match": {"ipv4": {"tag": "1000", "delete": True}},
}
]
}
}
}
result = create_route_maps(tgen, routemaps)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that metric falls back to original metric for ospf routes.")
dut = "r1"
protocol = "ospf"
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Delete the match clause with metric in route map.")
# Create route map
routemaps = {
"r0": {
"route_maps": {
"rmap_ipv4": [
{
"action": "permit",
"match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
}
]
}
}
}
result = create_route_maps(tgen, routemaps)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,612 @@
#!/usr/bin/python
#
# Copyright (c) 2020 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
# ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""OSPF Basic Functionality Automation."""
import os
import sys
import time
import pytest
import ipaddress
import json
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from mininet.topo import Topo
from lib.topogen import Topogen, get_topogen
# Import topoJson from lib, to create topology and initial configuration
from lib.common_config import (
start_topology,
write_test_header,
create_interfaces_cfg,
write_test_footer,
reset_config_on_routers,
verify_rib,
create_static_routes,
step,
shutdown_bringup_interface,
topo_daemons
)
from lib.bgp import verify_bgp_convergence, create_router_bgp
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.ospf import (
verify_ospf_neighbor,
clear_ospf,
verify_ospf_rib,
create_router_ospf,
)
# Global variables
topo = None
# number of retries.
nretry = 5
# Reading the data from JSON File for topology creation
jsonFile = "{}/ospf_rte_calc.json".format(CWD)
try:
with open(jsonFile, "r") as topoJson:
topo = json.load(topoJson)
except IOError:
assert False, "Could not read file {}".format(jsonFile)
NETWORK = {
"ipv4": [
"11.0.20.1/32",
"11.0.20.2/32",
"11.0.20.3/32",
"11.0.20.4/32",
"11.0.20.5/32",
]
}
TOPOOLOGY = """
Please view in a fixed-width font such as Courier.
+---+ A1 +---+
+R1 +------------+R2 |
+-+-+- +--++
| -- -- |
| -- A0 -- |
A0| ---- |
| ---- | A2
| -- -- |
| -- -- |
+-+-+- +-+-+
+R0 +-------------+R3 |
+---+ A3 +---+
"""
TESTCASES = """
1. Test OSPF intra area route calculations.
2. Test OSPF inter area route calculations.
3. Test OSPF redistribution of connected routes.
"""
class CreateTopo(Topo):
"""
Test topology builder.
* `Topo`: Topology object
"""
def build(self, *_args, **_opts):
"""Build function."""
tgen = get_topogen(self)
# Building topology from json file
build_topo_from_json(tgen, topo)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
global topo
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, topo)
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen, daemons)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
# Api call verify whether OSPF is converged
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
logger.info("Running setup_module() done")
def teardown_module(mod):
"""
Teardown the pytest environment.
* `mod`: module name
"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info(
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
def red_static(dut, config=True):
"""Local def for Redstribute static routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
else:
ospf_red = {
dut: {
"ospf": {
"redistribute": [{"redist_type": "static", "del_action": True}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase : Failed \n Error: {}".format(result)
def red_connected(dut, config=True):
"""Local def for Redstribute connected routes inside ospf."""
global topo
tgen = get_topogen()
if config:
ospf_red = {dut: {"ospf": {"redistribute": [{"redist_type": "connected"}]}}}
else:
ospf_red = {
dut: {
"ospf": {
"redistribute": [{"redist_type": "connected", "del_action": True}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase: Failed \n Error: {}".format(result)
# ##################################
# Test cases start here.
# ##################################
def test_ospf_redistribution_tc5_p0(request):
"""Test OSPF intra area route calculations."""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config.")
reset_config_on_routers(tgen)
step("Verify that OSPF neighbors are FULL.")
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("verify intra area route is calculated for r0-r3 interface ip in R1")
ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"]
ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
input_dict = {
"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]}
}
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Delete the ip address on newly configured interface of R0")
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
dut = "r1"
for num in range(0, nretry):
result = verify_ospf_rib(
tgen, dut, input_dict, next_hop=nh, expected=False)
if result is not True:
break
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
protocol = "ospf"
result = verify_rib(
tgen,
"ipv4",
dut,
input_dict,
protocol=protocol,
next_hop=nh,
attempts=5,
expected=False,
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Add back the deleted ip address on newly configured interface of R0")
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Shut no shut interface on R0")
dut = "r0"
intf = topo["routers"]["r0"]["links"]["r3"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
step("un shut the OSPF interface on R0")
dut = "r0"
shutdown_bringup_interface(tgen, dut, intf, True)
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
def test_ospf_redistribution_tc6_p0(request):
"""Test OSPF inter area route calculations."""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config.")
reset_config_on_routers(tgen)
step("Verify that OSPF neighbors are FULL.")
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("verify intra area route is calculated for r0-r3 interface ip in R1")
ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"]
ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
input_dict = {
"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]}
}
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Delete the ip address on newly configured loopback of R0")
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
dut = "r1"
for num in range(0, nretry):
result = verify_ospf_rib(
tgen, dut, input_dict, next_hop=nh, expected=False)
if result is not True:
break
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
protocol = "ospf"
result = verify_rib(
tgen,
"ipv4",
dut,
input_dict,
protocol=protocol,
next_hop=nh,
expected=False,
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Add back the deleted ip address on newly configured interface of R0")
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Shut no shut interface on R0")
dut = "r0"
intf = topo["routers"]["r0"]["links"]["r3"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
step("un shut the OSPF interface on R0")
dut = "r0"
shutdown_bringup_interface(tgen, dut, intf, True)
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
def test_ospf_redistribution_tc8_p1(request):
"""
Test OSPF redistribution of connected routes.
Verify OSPF redistribution of connected routes when bgp multi hop
neighbor is configured using ospf routes
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
global topo
step("Bring up the base config.")
step(
"Configure loopback interface on all routers, and redistribut"
"e connected routes into ospf"
)
reset_config_on_routers(tgen)
step(
"verify that connected routes -loopback is found in all routers"
"advertised/exchaged via ospf"
)
for rtr in topo["routers"]:
red_static(rtr)
red_connected(rtr)
for node in topo["routers"]:
input_dict = {
"r0": {
"static_routes": [
{
"network": topo["routers"][node]["links"]["lo"]["ipv4"],
"no_of_ip": 1,
}
]
}
}
for rtr in topo["routers"]:
result = verify_rib(tgen, "ipv4", rtr, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Configure E BGP multi hop using the loopback addresses.")
as_num = 100
for node in topo["routers"]:
as_num += 1
topo["routers"][node].update(
{
"bgp": {
"local_as": as_num,
"address_family": {"ipv4": {"unicast": {"neighbor": {}}}},
}
}
)
for node in topo["routers"]:
for rtr in topo["routers"]:
if node is not rtr:
topo["routers"][node]["bgp"]["address_family"]["ipv4"]["unicast"][
"neighbor"
].update(
{
rtr: {
"dest_link": {
"lo": {"source_link": "lo", "ebgp_multihop": 2}
}
}
}
)
result = create_router_bgp(tgen, topo, topo["routers"])
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that BGP neighbor is ESTABLISHED")
result = verify_bgp_convergence(tgen, topo)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step(
"Configure couple of static routes in R0 and "
"Redistribute static routes in R1 bgp."
)
for rtr in topo["routers"]:
ospf_red = {
rtr: {"ospf": {"redistribute": [{"redist_type": "static", "delete": True}]}}
}
result = create_router_ospf(tgen, topo, ospf_red)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
input_dict = {
"r0": {
"static_routes": [
{"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
]
}
}
result = create_static_routes(tgen, input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
configure_bgp_on_r0 = {
"r0": {
"bgp": {
"address_family": {
"ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}}
}
}
}
}
result = create_router_bgp(tgen, topo, configure_bgp_on_r0)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
protocol = "bgp"
for rtr in ["r1", "r2", "r3"]:
result = verify_rib(tgen, "ipv4", rtr, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Clear ospf neighbours in R0")
for rtr in topo["routers"]:
clear_ospf(tgen, rtr)
step("Verify that OSPF neighbours are reset and forms new adjacencies.")
# Api call verify whether OSPF is converged
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("Verify that BGP neighbours are reset and forms new adjacencies.")
result = verify_bgp_convergence(tgen, topo)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
protocol = "bgp"
for rtr in ["r1", "r2", "r3"]:
result = verify_rib(tgen, "ipv4", rtr, input_dict, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))

View File

@ -0,0 +1,781 @@
#!/usr/bin/python
#
# Copyright (c) 2020 by VMware, Inc. ("VMware")
# Used Copyright (c) 2018 by Network Device Education Foundation, Inc.
# ("NetDEF") in this file.
#
# Permission to use, copy, modify, and/or distribute this software
# for any purpose with or without fee is hereby granted, provided
# that the above copyright notice and this permission notice appear
# in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
#
"""OSPF Basic Functionality Automation."""
import os
import sys
import time
import pytest
import json
from copy import deepcopy
from ipaddress import IPv4Address
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
# pylint: disable=C0413
# Import topogen and topotest helpers
from mininet.topo import Topo
from lib.topogen import Topogen, get_topogen
import ipaddress
# Import topoJson from lib, to create topology and initial configuration
from lib.common_config import (
start_topology,
write_test_header,
write_test_footer,
reset_config_on_routers,
verify_rib,
create_static_routes,
step,
create_route_maps,
shutdown_bringup_interface,
create_interfaces_cfg,
topo_daemons
)
from lib.topolog import logger
from lib.topojson import build_topo_from_json, build_config_from_json
from lib.ospf import (
verify_ospf_neighbor,
config_ospf_interface,
clear_ospf,
verify_ospf_rib,
create_router_ospf,
verify_ospf_interface,
verify_ospf_database,
)
# Global variables
topo = None
# Reading the data from JSON File for topology creation
jsonFile = "{}/ospf_single_area.json".format(CWD)
try:
with open(jsonFile, "r") as topoJson:
topo = json.load(topoJson)
except IOError:
assert False, "Could not read file {}".format(jsonFile)
"""
TOPOOLOGY =
Please view in a fixed-width font such as Courier.
+---+ A1 +---+
+R1 +------------+R2 |
+-+-+- +--++
| -- -- |
| -- A0 -- |
A0| ---- |
| ---- | A2
| -- -- |
| -- -- |
+-+-+- +-+-+
+R0 +-------------+R3 |
+---+ A3 +---+
TESTCASES =
1. OSPF IFSM -Verify state change events on p2p network.
2. OSPF Timers - Verify OSPF interface timer hello interval functionality
3. OSPF Timers - Verify OSPF interface timer dead interval functionality
4. Verify ospf show commands with json output.
"""
class CreateTopo(Topo):
"""
Test topology builder.
* `Topo`: Topology object
"""
def build(self, *_args, **_opts):
"""Build function."""
tgen = get_topogen(self)
# Building topology from json file
build_topo_from_json(tgen, topo)
def setup_module(mod):
"""
Sets up the pytest environment
* `mod`: module name
"""
global topo
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
logger.info("=" * 40)
logger.info("Running setup_module to create topology")
# This function initiates the topology build with Topogen...
tgen = Topogen(CreateTopo, mod.__name__)
# ... and here it calls Mininet initialization functions.
# get list of daemons needs to be started for this suite.
daemons = topo_daemons(tgen, topo)
# Starting topology, create tmp files which are loaded to routers
# to start deamons and then start routers
start_topology(tgen, daemons)
# Creating configuration from JSON
build_config_from_json(tgen, topo)
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
logger.info("Running setup_module() done")
def teardown_module(mod):
"""
Teardown the pytest environment.
* `mod`: module name
"""
logger.info("Running teardown_module to delete topology")
tgen = get_topogen()
# Stop toplogy and Remove tmp files
tgen.stop_topology()
logger.info(
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
# ##################################
# Test cases start here.
# ##################################
def test_ospf_p2p_tc3_p0(request):
"""OSPF IFSM -Verify state change events on p2p network."""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config as per the topology")
reset_config_on_routers(tgen)
step(
"Verify that OSPF is subscribed to multi cast services "
"(All SPF, all DR Routers)."
)
step("Verify that interface is enabled in ospf.")
step("Verify that config is successful.")
dut = "r0"
input_dict = {
"r0": {
"links": {
"r3": {"ospf": {"mcastMemberOspfAllRouters": True, "ospfEnabled": True}}
}
}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Delete the ip address")
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": topo["routers"]["r0"]["links"]["r3"]["ipv4"],
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Change the ip on the R0 interface")
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
IPv4Address(unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(intf_ip.split("/")[1])
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
step("Verify that interface is enabled in ospf.")
dut = "r0"
input_dict = {
"r0": {
"links": {
"r3": {
"ospf": {
"ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
"r3"
]["ipv4"].split("/")[0],
"ipAddressPrefixlen": int(
topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
"ipv4"
].split("/")[1]
),
}
}
}
}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Modify the mask on the R0 interface")
ip_addr = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
mask = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
step("Delete the ip address")
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": ip_addr,
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Change the ip on the R0 interface")
topo_modify_change_ip = deepcopy(topo)
intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"]
topo_modify_change_ip["routers"]["r0"]["links"]["r3"]["ipv4"] = str(
IPv4Address(unicode(intf_ip.split("/")[0])) + 3
) + "/{}".format(int(intf_ip.split("/")[1]) + 1)
build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False)
step("Verify that interface is enabled in ospf.")
dut = "r0"
input_dict = {
"r0": {
"links": {
"r3": {
"ospf": {
"ipAddress": topo_modify_change_ip["routers"]["r0"]["links"][
"r3"
]["ipv4"].split("/")[0],
"ipAddressPrefixlen": int(
topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
"ipv4"
].split("/")[1]
),
}
}
}
}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo1 = {
"r0": {
"links": {
"r3": {
"ipv4": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
"ipv4"
],
"interface": topo_modify_change_ip["routers"]["r0"]["links"]["r3"][
"interface"
],
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
build_config_from_json(tgen, topo, save_bkup=False)
step("Change the area id on the interface")
input_dict = {
"r0": {
"links": {
"r3": {
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
"ospf": {"area": "0.0.0.0"},
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
input_dict = {
"r0": {
"links": {
"r3": {
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
"ospf": {"area": "0.0.0.1"},
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("Verify that interface is enabled in ospf.")
dut = "r0"
input_dict = {
"r0": {"links": {"r3": {"ospf": {"area": "0.0.0.1", "ospfEnabled": True}}}}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
input_dict = {
"r0": {
"links": {
"r3": {
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
"ospf": {"area": "0.0.0.1"},
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
input_dict = {
"r0": {
"links": {
"r3": {
"interface": topo["routers"]["r0"]["links"]["r3"]["interface"],
"ospf": {"area": "0.0.0.0"},
}
}
}
}
result = create_interfaces_cfg(tgen, input_dict)
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
# Api call verify whether BGP is converged
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
write_test_footer(tc_name)
def test_ospf_hello_tc10_p0(request):
"""
OSPF timers.
Verify OSPF interface timer hello interval functionality
"""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step("Bring up the base config as per the topology")
reset_config_on_routers(tgen)
step("modify hello timer from default value to some other value on r1")
topo1 = {
"r1": {
"links": {
"r0": {
"interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
"ospf": {"hello_interval": 11, "dead_interval": 12},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"verify that new timer value is configured and applied using "
"the show ip ospf interface command."
)
dut = "r1"
input_dict = {
"r1": {
"links": {"r0": {"ospf": {"timerMsecs": 11 * 1000, "timerDeadSecs": 12}}}
}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("modify hello timer from default value to r1 hello timer on r2")
topo1 = {
"r0": {
"links": {
"r1": {
"interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
"ospf": {"hello_interval": 11, "dead_interval": 12},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that new timer value is configured.")
input_dict = {
"r0": {
"links": {"r1": {"ospf": {"timerMsecs": 11 * 1000, "timerDeadSecs": 12}}}
}
}
dut = "r0"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("reconfigure the default hello timer value to default on r1 and r2")
topo1 = {
"r0": {
"links": {
"r1": {
"interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
"ospf": {"hello_interval": 10, "dead_interval": 40},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo1 = {
"r1": {
"links": {
"r0": {
"interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
"ospf": {"hello_interval": 10, "dead_interval": 40},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that new timer value is configured.")
input_dict = {
"r0": {
"links": {"r1": {"ospf": {"timerMsecs": 10 * 1000, "timerDeadSecs": 40}}}
}
}
dut = "r0"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("reconfigure the default hello timer value to default on r1 and r2")
topo1 = {
"r0": {
"links": {
"r1": {
"interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
"ospf": {"hello_interval": 10, "dead_interval": 40},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo1 = {
"r1": {
"links": {
"r0": {
"interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
"ospf": {"hello_interval": 10, "dead_interval": 40},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that new timer value is configured.")
input_dict = {
"r0": {
"links": {"r1": {"ospf": {"timerMsecs": 10 * 1000, "timerDeadSecs": 40}}}
}
}
dut = "r0"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step("configure hello timer = 1 on r1 and r2")
topo1 = {
"r0": {
"links": {
"r1": {
"interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
"ospf": {"hello_interval": 1, "dead_interval": 4},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo1 = {
"r1": {
"links": {
"r0": {
"interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
"ospf": {"hello_interval": 1, "dead_interval": 4},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that new timer value is configured.")
input_dict = {
"r0": {"links": {"r1": {"ospf": {"timerMsecs": 1 * 1000, "timerDeadSecs": 4}}}}
}
dut = "r0"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(" Configure hello timer = 65535")
topo1 = {
"r0": {
"links": {
"r1": {
"interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
"ospf": {"hello_interval": 65535, "dead_interval": 4},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo1 = {
"r1": {
"links": {
"r0": {
"interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
"ospf": {"hello_interval": 65535, "dead_interval": 4},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that new timer value is configured.")
input_dict = {
"r0": {
"links": {"r1": {"ospf": {"timerMsecs": 65535 * 1000, "timerDeadSecs": 4}}}
}
}
dut = "r0"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
step(" Try configuring timer values outside range for example 65536")
topo1 = {
"r0": {
"links": {
"r1": {
"interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
"ospf": {"hello_interval": 65536, "dead_interval": 4},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
)
step("Unconfigure the hello timer from the interface from r1 and r2.")
topo1 = {
"r1": {
"links": {
"r0": {
"interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
"ospf": {"hello_interval": 65535},
"delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Verify that timer value is deleted from intf & " "set to default value 40 sec."
)
input_dict = {"r1": {"links": {"r0": {"ospf": {"timerMsecs": 10 * 1000}}}}}
dut = "r1"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
def test_ospf_show_p1(request):
"""Verify ospf show commands with json output."""
tc_name = request.node.name
write_test_header(tc_name)
tgen = get_topogen()
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
global topo
step(" Bring up the base config as per the topology")
reset_config_on_routers(tgen)
ospf_covergence = verify_ospf_neighbor(tgen, topo)
assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
)
dut = "r1"
input_dict = {
"r1": {
"links": {
"r0": {
"ospf": {
"ifUp": True,
"ifFlags": "<UP,BROADCAST,RUNNING,MULTICAST>",
"ospfEnabled": True,
"ipAddressPrefixlen": 24,
"ospfIfType": "Broadcast",
"area": "0.0.0.0",
"networkType": "BROADCAST",
"cost": 10,
"transmitDelaySecs": 1,
"state": "DR",
"priority": 1,
"mcastMemberOspfAllRouters": True,
"timerMsecs": 1000,
"timerDeadSecs": 4,
"timerWaitSecs": 4,
"timerRetransmitSecs": 5,
"nbrCount": 1,
"nbrAdjacentCount": 1,
}
}
}
}
}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
# show ip ospf route
ip = topo["routers"]["r0"]["links"]["r3"]["ipv4"]
ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
nh = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0]
input_dict = {
"r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]}
}
dut = "r1"
result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh)
assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))