summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/topotests/lib/common_config.py7
-rw-r--r--tests/topotests/lib/ospf.py8
-rw-r--r--tests/topotests/lib/topogen.py8
-rw-r--r--tests/topotests/lib/topotest.py1
-rwxr-xr-xtests/topotests/ospf_multi_vrf_bgp_route_leak/__init__.py0
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf57
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/ospf-vrf-default.txt19
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/ospf-vrf-neno.txt12
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt9
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt6
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf62
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/ospf-vrf-default.txt20
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/ospf-vrf-ray.txt15
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt10
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt9
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf22
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/ospf-vrf-default.txt17
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt8
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf22
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/ospf-vrf-default.txt17
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt7
-rw-r--r--tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py243
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_asbr_summary_type7_lsa.json202
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_dual_stack.json312
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp.json36
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp_lan.json264
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_lan.json140
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_nssa2.json197
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_routemaps.json59
-rw-r--r--tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json17
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py1200
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py400
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py482
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py416
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py375
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py957
-rw-r--r--tests/topotests/zebra_rib/test_zebra_rib.py57
37 files changed, 5538 insertions, 155 deletions
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index c0572fca4c..005896b01c 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -2536,6 +2536,7 @@ def create_route_maps(tgen, input_dict, build=False):
ipv6_data = set_data.setdefault("ipv6", {})
local_preference = set_data.setdefault("locPrf", None)
metric = set_data.setdefault("metric", None)
+ metric_type = set_data.setdefault("metric-type", None)
as_path = set_data.setdefault("path", {})
weight = set_data.setdefault("weight", None)
community = set_data.setdefault("community", {})
@@ -2559,7 +2560,11 @@ def create_route_maps(tgen, input_dict, build=False):
# Metric
if metric:
- rmap_data.append("set metric {} \n".format(metric))
+ del_comm = set_data.setdefault("delete", None)
+ if del_comm:
+ rmap_data.append("no set metric {}".format(metric))
+ else:
+ rmap_data.append("set metric {}".format(metric))
# Origin
if origin:
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
index 8d2bf12af2..e7ea7d32ba 100644
--- a/tests/topotests/lib/ospf.py
+++ b/tests/topotests/lib/ospf.py
@@ -1668,7 +1668,7 @@ def verify_ospf6_rib(
logger.info("Checking router %s RIB:", router)
# Verifying RIB routes
- command = "show ipv6 ospf route"
+ command = "show ipv6 ospf route detail"
found_routes = []
missing_routes = []
@@ -1710,6 +1710,8 @@ def verify_ospf6_rib(
# Generating IPs for verification
ip_list = generate_ips(network, no_of_ip)
+ if len(ip_list) == 1:
+ ip_list = [network]
st_found = False
nh_found = False
for st_rt in ip_list:
@@ -1846,7 +1848,7 @@ def verify_ospf6_rib(
return errormsg
if metric is not None:
- if "type2cost" not in ospf_rib_json[st_rt]:
+ if "metricCostE2" not in ospf_rib_json[st_rt]:
errormsg = (
"[DUT: {}]: metric is"
" not present for"
@@ -1854,7 +1856,7 @@ def verify_ospf6_rib(
)
return errormsg
- if metric != ospf_rib_json[st_rt]["type2cost"]:
+ if metric != ospf_rib_json[st_rt]["metricCostE2"]:
errormsg = (
"[DUT: {}]: metric value "
"{} is not matched for "
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index a83ae7071f..4ed5b2f825 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -804,9 +804,11 @@ class TopoRouter(TopoGear):
for daemon in self.RD:
# This will not work for all daemons
daemonstr = self.RD.get(daemon).rstrip("d")
- result = self.run(
- "grep 'router {}' {}".format(daemonstr, source)
- ).strip()
+ if daemonstr == "pim":
+ grep_cmd = "grep 'ip {}' {}".format(daemonstr, source)
+ else:
+ grep_cmd = "grep 'router {}' {}".format(daemonstr, source)
+ result = self.run(grep_cmd).strip()
if result:
self.load_config(daemon)
else:
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 62b6a8a70e..e786ae02cd 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -737,6 +737,7 @@ def proto_name_to_number(protocol):
"sharp": "194",
"pbr": "195",
"static": "196",
+ "ospf6": "197",
}.get(
protocol, protocol
) # default return same as input
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/__init__.py b/tests/topotests/ospf_multi_vrf_bgp_route_leak/__init__.py
new file mode 100755
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/__init__.py
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf
new file mode 100644
index 0000000000..e365e25772
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/frr.conf
@@ -0,0 +1,57 @@
+!
+hostname r1
+password zebra
+log file /tmp/r1-frr.log
+!
+interface r1-eth0
+ ip address 10.0.1.1/24
+!
+interface r1-eth1
+ ip address 10.0.20.1/24
+!
+interface r1-eth2 vrf neno
+ ip address 10.0.30.1/24
+!
+ip forwarding
+!
+router ospf
+ ospf router-id 10.0.255.1
+ redistribute bgp
+ network 10.0.1.0/24 area 0
+ network 10.0.20.0/24 area 0
+!
+router ospf vrf neno
+ ospf router-id 10.0.255.1
+ redistribute bgp
+ network 10.0.30.0/24 area 0
+!
+!
+router bgp 99
+ no bgp ebgp-requires-policy
+ address-family ipv4 unicast
+ redistribute connected
+ redistribute ospf
+ import vrf neno
+ !
+!
+router bgp 99 vrf neno
+ no bgp ebgp-requires-policy
+ address-family ipv4 unicast
+ redistribute connected
+ redistribute ospf
+ import vrf route-map rmap
+ import vrf default
+ !
+!
+!!!!!!!!!!!!!!!!!!!!!
+! VRFs neno and ray subnets
+ip prefix-list nets seq 5 permit 10.0.3.0/24
+ip prefix-list nets seq 10 permit 10.0.30.0/24
+ip prefix-list nets seq 15 permit 10.0.4.0/24
+ip prefix-list nets seq 20 permit 10.0.40.0/24
+ip prefix-list nets seq 25 deny any
+!
+route-map rmap permit 10
+ match ip address prefix-list nets
+ exit
+!
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/ospf-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/ospf-vrf-default.txt
new file mode 100644
index 0000000000..45b7fad334
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/ospf-vrf-default.txt
@@ -0,0 +1,19 @@
+VRF Name: default
+============ OSPF network routing table ============
+N 10.0.1.0/24 [10] area: 0.0.0.0
+ directly attached to r1-eth0
+N 10.0.2.0/24 [20] area: 0.0.0.0
+ via 10.0.20.2, r1-eth1
+N 10.0.20.0/24 [10] area: 0.0.0.0
+ directly attached to r1-eth1
+
+============ OSPF router routing table =============
+R 10.0.255.2 [10] area: 0.0.0.0, ASBR
+ via 10.0.20.2, r1-eth1
+
+============ OSPF external routing table ===========
+N E2 10.0.4.0/24 [10/20] tag: 0
+ via 10.0.20.2, r1-eth1
+N E2 10.0.40.0/24 [10/20] tag: 0
+ via 10.0.20.2, r1-eth1
+
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/ospf-vrf-neno.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/ospf-vrf-neno.txt
new file mode 100644
index 0000000000..cc2c1baa17
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/ospf-vrf-neno.txt
@@ -0,0 +1,12 @@
+VRF Name: neno
+============ OSPF network routing table ============
+N 10.0.3.0/24 [20] area: 0.0.0.0
+ via 10.0.30.3, r1-eth2
+N 10.0.30.0/24 [10] area: 0.0.0.0
+ directly attached to r1-eth2
+
+============ OSPF router routing table =============
+R 10.0.255.3 [10] area: 0.0.0.0, ASBR
+ via 10.0.30.3, r1-eth2
+
+============ OSPF external routing table ===========
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
new file mode 100644
index 0000000000..86c089ab3b
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-default.txt
@@ -0,0 +1,9 @@
+O 10.0.1.0/24 [110/10] is directly connected, r1-eth0, weight 1, XX:XX:XX
+C>* 10.0.1.0/24 is directly connected, r1-eth0, XX:XX:XX
+O>* 10.0.2.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
+B>* 10.0.3.0/24 [20/20] via 10.0.30.3, r1-eth2 (vrf neno), weight 1, XX:XX:XX
+O>* 10.0.4.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
+O 10.0.20.0/24 [110/10] is directly connected, r1-eth1, weight 1, XX:XX:XX
+C>* 10.0.20.0/24 is directly connected, r1-eth1, XX:XX:XX
+B>* 10.0.30.0/24 [20/0] is directly connected, r1-eth2 (vrf neno), weight 1, XX:XX:XX
+O>* 10.0.40.0/24 [110/20] via 10.0.20.2, r1-eth1, weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt
new file mode 100644
index 0000000000..4e818eb6f1
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r1/zebra-vrf-neno.txt
@@ -0,0 +1,6 @@
+VRF neno:
+O>* 10.0.3.0/24 [110/20] via 10.0.30.3, r1-eth2, weight 1, XX:XX:XX
+B>* 10.0.4.0/24 [20/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX
+O 10.0.30.0/24 [110/10] is directly connected, r1-eth2, weight 1, XX:XX:XX
+C>* 10.0.30.0/24 is directly connected, r1-eth2, XX:XX:XX
+B>* 10.0.40.0/24 [20/20] via 10.0.20.2, r1-eth1 (vrf default), weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf
new file mode 100644
index 0000000000..e87899ca77
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/frr.conf
@@ -0,0 +1,62 @@
+!
+hostname r2
+password zebra
+log file /tmp/r2-frr.log
+!
+interface r2-eth0
+ ip address 10.0.2.2/24
+!
+interface r2-eth1
+ ip address 10.0.20.2/24
+!
+ip route 0.0.0.0/0 10.0.20.1
+!
+interface r2-eth2 vrf ray
+ ip address 10.0.40.2/24
+!
+ip forwarding
+!
+vrf ray
+ ip protocol bgp route-map rmap
+ exit-vrf
+!
+router ospf
+ ospf router-id 10.0.255.2
+ redistribute bgp
+ network 10.0.2.0/24 area 0
+ network 10.0.20.0/24 area 0
+!
+router ospf vrf ray
+ ospf router-id 10.0.255.1
+ redistribute bgp
+ network 10.0.40.0/24 area 0
+!
+
+router bgp 99
+ no bgp ebgp-requires-policy
+ address-family ipv4 unicast
+ redistribute connected
+ redistribute ospf
+ import vrf ray
+ !
+!
+router bgp 99 vrf ray
+ no bgp ebgp-requires-policy
+ address-family ipv4 unicast
+ redistribute connected
+ redistribute ospf
+ import vrf default
+ !
+!
+!!!!!!!!!!!!!!!!!!!!!
+! VRFs neno and ray subnets
+ip prefix-list nets seq 5 permit 10.0.3.0/24
+ip prefix-list nets seq 10 permit 10.0.30.0/24
+ip prefix-list nets seq 15 permit 10.0.4.0/24
+ip prefix-list nets seq 20 permit 10.0.40.0/24
+ip prefix-list nets seq 25 deny any
+!
+route-map rmap permit 10
+ match ip address prefix-list nets
+ exit
+!
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/ospf-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/ospf-vrf-default.txt
new file mode 100644
index 0000000000..77b8038b70
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/ospf-vrf-default.txt
@@ -0,0 +1,20 @@
+VRF Name: default
+============ OSPF network routing table ============
+N 10.0.1.0/24 [20] area: 0.0.0.0
+ via 10.0.20.1, r2-eth1
+N 10.0.2.0/24 [10] area: 0.0.0.0
+ directly attached to r2-eth0
+N 10.0.20.0/24 [10] area: 0.0.0.0
+ directly attached to r2-eth1
+
+============ OSPF router routing table =============
+R 10.0.255.1 [10] area: 0.0.0.0, ASBR
+ via 10.0.20.1, r2-eth1
+
+============ OSPF external routing table ===========
+N E2 10.0.3.0/24 [10/20] tag: 0
+ via 10.0.20.1, r2-eth1
+N E2 10.0.30.0/24 [10/20] tag: 0
+ via 10.0.20.1, r2-eth1
+
+
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/ospf-vrf-ray.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/ospf-vrf-ray.txt
new file mode 100644
index 0000000000..b70ee9d5a6
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/ospf-vrf-ray.txt
@@ -0,0 +1,15 @@
+VRF Name: ray
+============ OSPF network routing table ============
+N 10.0.4.0/24 [20] area: 0.0.0.0
+ via 10.0.40.4, r2-eth2
+N 10.0.40.0/24 [10] area: 0.0.0.0
+ directly attached to r2-eth2
+
+============ OSPF router routing table =============
+R 10.0.255.4 [10] area: 0.0.0.0, ASBR
+ via 10.0.40.4, r2-eth2
+
+============ OSPF external routing table ===========
+
+
+
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
new file mode 100644
index 0000000000..9681d8a04e
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-default.txt
@@ -0,0 +1,10 @@
+S>* 0.0.0.0/0 [1/0] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
+O>* 10.0.1.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
+O 10.0.2.0/24 [110/10] is directly connected, r2-eth0, weight 1, XX:XX:XX
+C>* 10.0.2.0/24 is directly connected, r2-eth0, XX:XX:XX
+O>* 10.0.3.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
+B>* 10.0.4.0/24 [20/20] via 10.0.40.4, r2-eth2 (vrf ray), weight 1, XX:XX:XX
+O 10.0.20.0/24 [110/10] is directly connected, r2-eth1, weight 1, XX:XX:XX
+C>* 10.0.20.0/24 is directly connected, r2-eth1, XX:XX:XX
+O>* 10.0.30.0/24 [110/20] via 10.0.20.1, r2-eth1, weight 1, XX:XX:XX
+B>* 10.0.40.0/24 [20/0] is directly connected, r2-eth2 (vrf ray), weight 1, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
new file mode 100644
index 0000000000..ce9903ae71
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r2/zebra-vrf-ray.txt
@@ -0,0 +1,9 @@
+VRF ray:
+B 10.0.1.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
+B 10.0.2.0/24 [20/0] is directly connected, r2-eth0 (vrf default) inactive, weight 1, XX:XX:XX
+B>* 10.0.3.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
+O>* 10.0.4.0/24 [110/20] via 10.0.40.4, r2-eth2, weight 1, XX:XX:XX
+B 10.0.20.0/24 [20/0] is directly connected, r2-eth1 (vrf default) inactive, weight 1, XX:XX:XX
+B>* 10.0.30.0/24 [20/20] via 10.0.20.1, r2-eth1 (vrf default), weight 1, XX:XX:XX
+O 10.0.40.0/24 [110/10] is directly connected, r2-eth2, weight 1, XX:XX:XX
+C>* 10.0.40.0/24 is directly connected, r2-eth2, XX:XX:XX
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf
new file mode 100644
index 0000000000..2657f589d8
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/frr.conf
@@ -0,0 +1,22 @@
+!
+hostname r3
+password zebra
+log file /tmp/r3-frr.log
+!
+interface r3-eth0
+ ip address 10.0.3.3/24
+!
+interface r3-eth1
+ ip address 10.0.30.3/24
+!
+ip forwarding
+!
+!
+router ospf
+ ospf router-id 10.0.255.3
+ redistribute kernel
+ redistribute connected
+ redistribute static
+ network 10.0.3.0/24 area 0
+ network 10.0.30.0/24 area 0
+!
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/ospf-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/ospf-vrf-default.txt
new file mode 100644
index 0000000000..3eb5690834
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/ospf-vrf-default.txt
@@ -0,0 +1,17 @@
+VRF Name: default
+============ OSPF network routing table ============
+N 10.0.3.0/24 [10] area: 0.0.0.0
+ directly attached to r3-eth0
+N 10.0.30.0/24 [10] area: 0.0.0.0
+ directly attached to r3-eth1
+
+============ OSPF router routing table =============
+R 10.0.255.1 [10] area: 0.0.0.0, ASBR
+ via 10.0.30.1, r3-eth1
+
+============ OSPF external routing table ===========
+N E2 10.0.4.0/24 [10/20] tag: 0
+ via 10.0.30.1, r3-eth1
+N E2 10.0.40.0/24 [10/20] tag: 0
+ via 10.0.30.1, r3-eth1
+
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt
new file mode 100644
index 0000000000..f6f861b73b
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r3/zebra-vrf-default.txt
@@ -0,0 +1,8 @@
+O 10.0.3.0/24 [110/10] is directly connected, r3-eth0, weight 1, XX:XX:XX
+C>* 10.0.3.0/24 is directly connected, r3-eth0, XX:XX:XX
+O>* 10.0.4.0/24 [110/20] via 10.0.30.1, r3-eth1, weight 1, XX:XX:XX
+O 10.0.30.0/24 [110/10] is directly connected, r3-eth1, weight 1, XX:XX:XX
+C>* 10.0.30.0/24 is directly connected, r3-eth1, XX:XX:XX
+O>* 10.0.40.0/24 [110/20] via 10.0.30.1, r3-eth1, weight 1, XX:XX:XX
+
+
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf
new file mode 100644
index 0000000000..79d8077062
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/frr.conf
@@ -0,0 +1,22 @@
+!
+hostname r4
+password zebra
+log file /tmp/r4-frr.log
+!
+interface r4-eth0
+ ip address 10.0.4.4/24
+!
+interface r4-eth1
+ ip address 10.0.40.4/24
+!
+ip forwarding
+!
+!
+router ospf
+ ospf router-id 10.0.255.4
+ redistribute kernel
+ redistribute connected
+ redistribute static
+ network 10.0.4.0/24 area 0
+ network 10.0.40.0/24 area 0
+!
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/ospf-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/ospf-vrf-default.txt
new file mode 100644
index 0000000000..ad799af996
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/ospf-vrf-default.txt
@@ -0,0 +1,17 @@
+VRF Name: default
+============ OSPF network routing table ============
+N 10.0.4.0/24 [10] area: 0.0.0.0
+ directly attached to r4-eth0
+N 10.0.40.0/24 [10] area: 0.0.0.0
+ directly attached to r4-eth1
+
+============ OSPF router routing table =============
+R 10.0.255.1 [10] area: 0.0.0.0, ASBR
+ via 10.0.40.2, r4-eth1
+
+============ OSPF external routing table ===========
+N E2 10.0.3.0/24 [10/20] tag: 0
+ via 10.0.40.2, r4-eth1
+N E2 10.0.30.0/24 [10/20] tag: 0
+ via 10.0.40.2, r4-eth1
+
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt
new file mode 100644
index 0000000000..b6be5e7fdb
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/r4/zebra-vrf-default.txt
@@ -0,0 +1,7 @@
+O>* 10.0.3.0/24 [110/20] via 10.0.40.2, r4-eth1, weight 1, XX:XX:XX
+O 10.0.4.0/24 [110/10] is directly connected, r4-eth0, weight 1, XX:XX:XX
+C>* 10.0.4.0/24 is directly connected, r4-eth0, XX:XX:XX
+O>* 10.0.30.0/24 [110/20] via 10.0.40.2, r4-eth1, weight 1, XX:XX:XX
+O 10.0.40.0/24 [110/10] is directly connected, r4-eth1, weight 1, XX:XX:XX
+C>* 10.0.40.0/24 is directly connected, r4-eth1, XX:XX:XX
+
diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py
new file mode 100644
index 0000000000..0b6b50ec06
--- /dev/null
+++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py
@@ -0,0 +1,243 @@
+#!/usr/bin/env python
+
+#
+# test_ospf_multi_vrf_bgp_route_leak.py
+#
+# Copyright (c) 2022 ATCorp
+# Jafar Al-Gharaibeh
+#
+# 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 NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF 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.
+#
+
+import os
+import sys
+from functools import partial
+import pytest
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+
+"""
+test_ospf_multi_vrf_bgp_route_leak.py: Test OSPF with multi vrf setup and route leaking.
+"""
+
+TOPOLOGY = """
+ bgp route leaking (connected/ospf), vrfs: neno <==> default <==> ray
+ routes leaking to vrfs are limited to neno and ray routes.
+
+ 10.0.1.1/24
+ ^
+ |vrf:default
+ +---+---+
+ 10.0.30.0/24 .1| |.1
+ +-----------------+ R1 +
+ | vrf:neno | |
+ | +---+---+ ^
+ |.3 .1|vrf:default | 10.0.4.4/24
+ +---+---+ | +---+---+
+ | | 10.0.20.0/24 | |
+ | R3 | | | R4 |
+ | | |.2 | |
+ +---+---+ +---+---+ +---+---+
+ | | | vrf:ray |.4
+ v | R2 +----------------+
+10.0.3.3/24 | |.2 10.0.40.0/24
+ +---+---+
+ |
+ v
+ 10.0.2.2/24
+
+"""
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# Required to instantiate the topology builder class.
+
+pytestmark = [pytest.mark.ospfd, pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ "Build function"
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ # Create a empty network for router 1
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+
+ # Create a empty network for router 2
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+
+ # Create a empty network for router 3
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"])
+
+ # Create a empty network for router 4
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r4"])
+
+ # Interconect router 1, 2
+ switch = tgen.add_switch("s1-2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ # Interconect router 1, 3
+ switch = tgen.add_switch("s1-3")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+ # Interconect router 2, 4
+ switch = tgen.add_switch("s2-4")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+ logger.info("OSPF Multi VRF Topology with BGP route leaking:\n {}".format(TOPOLOGY))
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ r1_vrf_setup_cmds = [
+ "ip link add name neno type vrf table 11",
+ "ip link set dev neno up",
+ "ip link set dev r1-eth2 vrf neno up",
+ ]
+ r2_vrf_setup_cmds = [
+ "ip link add name ray type vrf table 11",
+ "ip link set dev ray up",
+ "ip link set dev r2-eth2 vrf ray up",
+ ]
+
+ # Starting Routers
+ router_list = tgen.routers()
+
+ # Create VRFs on r1/r2 and bind to interfaces
+ for cmd in r1_vrf_setup_cmds:
+ tgen.net["r1"].cmd(cmd)
+ for cmd in r2_vrf_setup_cmds:
+ tgen.net["r2"].cmd(cmd)
+
+ logger.info("Testing OSPF VRF support")
+
+ for rname, router in router_list.items():
+ logger.info("Loading router %s" % rname)
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ # Initialize all routers.
+ tgen.start_router()
+ for router in router_list.values():
+ if router.has_version("<", "4.0"):
+ tgen.set_error("unsupported version")
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+# Shared test function to validate expected output.
+def compare_show_ip_route_vrf(rname, expected, vrf_name):
+ """
+ Calls 'show ip route vrf [vrf_name] route' and compare the obtained
+ result with the expected output.
+ """
+ tgen = get_topogen()
+ current = topotest.ip4_route_zebra(tgen.gears[rname], vrf_name)
+ ret = topotest.difflines(
+ current, expected, title1="Current output", title2="Expected output"
+ )
+ return ret
+
+
+def test_ospf_convergence():
+ "Test OSPF daemon convergence"
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ for rname, router in tgen.routers().items():
+ logger.info('Waiting for router "%s" convergence', rname)
+
+ for vrf in ["default", "neno", "ray"]:
+ # Load expected results from the command
+ reffile = os.path.join(CWD, "{}/ospf-vrf-{}.txt".format(rname, vrf))
+ if vrf == "default" or os.path.exists(reffile):
+ expected = open(reffile).read()
+
+ # Run test function until we get an result. Wait at most 80 seconds.
+ test_func = partial(
+ topotest.router_output_cmp,
+ router,
+ "show ip ospf vrf {} route".format(vrf),
+ expected,
+ )
+ result, diff = topotest.run_and_expect(
+ test_func, "", count=80, wait=1
+ )
+ assertmsg = "OSPF did not converge on {}:\n{}".format(rname, diff)
+ assert result, assertmsg
+
+
+def test_ospf_kernel_route():
+ "Test OSPF kernel route installation"
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip("skipped because of router(s) failure")
+
+ rlist = tgen.routers().values()
+ for router in rlist:
+ logger.info('Checking OSPF IPv4 kernel routes in "%s"', router.name)
+ for vrf in ["default", "neno", "ray"]:
+ reffile = os.path.join(CWD, "{}/zebra-vrf-{}.txt".format(router.name, vrf))
+ if vrf == "default" or os.path.exists(reffile):
+ expected = open(reffile).read()
+ # Run test function until we get an result. Wait at most 80 seconds.
+ test_func = partial(
+ compare_show_ip_route_vrf, router.name, expected, vrf
+ )
+ result, diff = topotest.run_and_expect(
+ test_func, "", count=80, wait=1
+ )
+ assertmsg = 'OSPF IPv4 route mismatch in router "{}": {}'.format(
+ router.name, diff
+ )
+ assert result, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_asbr_summary_type7_lsa.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_asbr_summary_type7_lsa.json
new file mode 100644
index 0000000000..27b36aea17
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_asbr_summary_type7_lsa.json
@@ -0,0 +1,202 @@
+{
+ "address_types": [
+ "ipv6"
+ ],
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3-link0": {
+ "ipv6": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto"
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link0": {
+ "ipv6": "auto",
+ "description": "DummyIntftoR1",
+ "ospf6": {
+ "area": "0.0.0.3"
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.3",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_dual_stack.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_dual_stack.json
new file mode 100644
index 0000000000..5555d9291e
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_dual_stack.json
@@ -0,0 +1,312 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ },
+ "ospf": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "description": "DummyIntftoR1",
+ "ospf6": {
+ "area": "0.0.0.0"
+ },
+ "ospf": {
+ "area": "0.0.0.0"
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "1.0.4.17",
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ },
+ "ospf": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp.json
index c928093925..22f46e2bf6 100644
--- a/tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp.json
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp.json
@@ -2,6 +2,7 @@
"address_types": [
"ipv6"
],
+
"ipv6base": "fd00::",
"ipv6mask": 64,
"link_ip_start": {
@@ -9,6 +10,7 @@
"v6mask": 64
},
"lo_prefix": {
+
"ipv6": "2001:db8:f::",
"v6mask": 128
},
@@ -21,6 +23,7 @@
},
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -29,6 +32,7 @@
},
"r1-link1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -37,6 +41,7 @@
},
"r1-link2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -45,6 +50,7 @@
},
"r1-link3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -53,6 +59,7 @@
},
"r1-link4": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -61,6 +68,7 @@
},
"r1-link5": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -69,6 +77,7 @@
},
"r1-link6": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -77,6 +86,7 @@
},
"r1-link7": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -85,6 +95,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -93,6 +104,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -101,6 +113,7 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.0",
"neighbors": {
@@ -139,6 +152,7 @@
},
"r0": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -147,6 +161,7 @@
},
"r0-link1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -155,6 +170,7 @@
},
"r0-link2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -163,6 +179,7 @@
},
"r0-link3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -171,6 +188,7 @@
},
"r0-link4": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -179,6 +197,7 @@
},
"r0-link5": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -187,6 +206,7 @@
},
"r0-link6": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -195,6 +215,7 @@
},
"r0-link7": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -203,6 +224,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -211,6 +233,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -222,6 +245,7 @@
"description": "DummyIntftoR3"
}
},
+
"ospf6": {
"router_id": "100.1.1.1",
"neighbors": {
@@ -260,6 +284,7 @@
},
"r0": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -268,6 +293,7 @@
},
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -276,6 +302,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -283,6 +310,7 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.2",
"neighbors": {
@@ -300,6 +328,7 @@
},
"r0": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -309,6 +338,7 @@
},
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -317,6 +347,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -326,14 +357,13 @@
"r1-link0": {
"ipv6": "auto",
"description": "DummyIntftoR1",
- "ospf": {
- "area": "0.0.0.0"
- },
+
"ospf6": {
"area": "0.0.0.0"
}
}
},
+
"ospf6": {
"router_id": "100.1.1.3",
"neighbors": {
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp_lan.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp_lan.json
new file mode 100644
index 0000000000..53b3f49e62
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_ecmp_lan.json
@@ -0,0 +1,264 @@
+{
+ "address_types": [
+ "ipv6"
+ ],
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "switches": {
+ "s1": {
+ "links": {
+ "r0": {
+
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 98
+ }
+ },
+ "r1": {
+
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 99
+ }
+ },
+ "r2": {
+
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r3": {
+
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r4": {
+
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r5": {
+
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r6": {
+
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r7": {
+
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ }
+ }
+ }
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+
+ "ipv6": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {},
+ "r4": {},
+ "r5": {},
+ "r6": {},
+ "r7": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3-link0": {
+
+ "ipv6": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {},
+ "r4": {},
+ "r5": {},
+ "r6": {},
+ "r7": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+
+ "ipv6": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+
+ "ipv6": "auto",
+ "description": "DummyIntftoR1"
+
+ }
+ },
+
+ "ospf6": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {
+
+ "ipv6": "auto",
+ "type": "loopback"
+ }
+ },
+
+ "ospf6": {
+ "router_id": "100.1.1.4",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ },
+ "r5": {
+ "links": {
+ "lo": {
+
+ "ipv6": "auto",
+ "type": "loopback"
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.5",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ },
+ "r6": {
+ "links": {
+ "lo": {
+
+ "ipv6": "auto",
+ "type": "loopback"
+ }
+ },
+
+ "ospf6": {
+ "router_id": "100.1.1.6",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ },
+ "r7": {
+ "links": {
+ "lo": {
+
+ "ipv6": "auto",
+ "type": "loopback"
+ }
+ },
+
+ "ospf6": {
+ "router_id": "100.1.1.7",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_lan.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_lan.json
new file mode 100644
index 0000000000..3a2fc022e5
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_lan.json
@@ -0,0 +1,140 @@
+{
+ "address_types": [
+ "ipv6"
+ ],
+
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "switches": {
+ "s1": {
+ "links": {
+ "r0": {
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 98
+ }
+ },
+ "r1": {
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 99
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+
+ "ospf6": {
+ "area": "0.0.0.3",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "priority": 0
+ }
+ }
+ }
+ }
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ }
+ },
+
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3-link0": {
+ "ipv6": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ }
+ },
+
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r0": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv6": "auto",
+ "description": "DummyIntftoR1"
+ }
+ },
+
+ "ospf6": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r0": {},
+ "r1": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_nssa2.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_nssa2.json
new file mode 100644
index 0000000000..b1432b9bee
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_nssa2.json
@@ -0,0 +1,197 @@
+
+{
+ "address_types": [
+ "ipv6"
+ ],
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3-link0": {
+ "ipv6": "auto",
+ "description": "DummyIntftoR3"
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto"
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r3": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r0": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4,
+ "network": "point-to-point"
+ }
+ },
+ "r1": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r2": {
+ "ipv6": "auto",
+ "ospf6": {
+ "area": "0.0.0.2",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }
+ },
+ "r1-link0": {
+ "ipv6": "auto",
+ "description": "DummyIntftoR1",
+ "ospf6": {
+ "area": "0.0.0.3"
+ }
+ }
+ },
+ "ospf6": {
+ "router_id": "100.1.1.3",
+ "area": [
+ {
+ "id": "0.0.0.2",
+ "type": "nssa"
+ }
+ ],
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_routemaps.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_routemaps.json
index 226f84f320..a1c7bd72d4 100644
--- a/tests/topotests/ospfv3_basic_functionality/ospfv3_routemaps.json
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_routemaps.json
@@ -1,14 +1,26 @@
{
- "address_types": ["ipv6"],
+ "address_types": [
+ "ipv6"
+ ],
+
"ipv6base": "fd00::",
"ipv6mask": 64,
- "link_ip_start": {"ipv6": "fd00::", "v6mask": 64},
- "lo_prefix": {"ipv6": "2001:db8:f::", "v6mask": 128},
+ "link_ip_start": {
+
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
"routers": {
"r0": {
"links": {
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -17,6 +29,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -25,6 +38,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -32,15 +46,21 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.0",
- "neighbors": {"r1": {}, "r2": {}, "r3": {}}
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r3": {}
+ }
}
},
"r1": {
"links": {
"r0": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -49,6 +69,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -57,6 +78,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -64,15 +86,21 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.1",
- "neighbors": {"r0": {}, "r2": {}, "r3": {}}
+ "neighbors": {
+ "r0": {},
+ "r2": {},
+ "r3": {}
+ }
}
},
"r2": {
"links": {
"r0": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -81,6 +109,7 @@
},
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -89,6 +118,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -96,15 +126,21 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.2",
- "neighbors": {"r1": {}, "r0": {}, "r3": {}}
+ "neighbors": {
+ "r1": {},
+ "r0": {},
+ "r3": {}
+ }
}
},
"r3": {
"links": {
"r0": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -113,6 +149,7 @@
},
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -121,6 +158,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -128,10 +166,15 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.3",
- "neighbors": {"r0": {}, "r1": {}, "r2": {}}
+ "neighbors": {
+ "r0": {},
+ "r1": {},
+ "r2": {}
+ }
}
}
}
-}
+} \ No newline at end of file
diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json
index 3669b3a554..e70481ace9 100644
--- a/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json
+++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_rte_calc.json
@@ -5,13 +5,16 @@
"address_types": [
"ipv6"
],
+
"ipv6base": "fd00::",
"ipv6mask": 64,
"link_ip_start": {
+
"ipv6": "fd00::",
"v6mask": 64
},
"lo_prefix": {
+
"ipv6": "2001:db8:f::",
"v6mask": 128
},
@@ -24,6 +27,7 @@
},
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -32,6 +36,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -40,6 +45,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -47,6 +53,7 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.0",
"neighbors": {
@@ -63,6 +70,7 @@
},
"r0": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -71,6 +79,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -79,6 +88,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -86,6 +96,7 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.1",
"neighbors": {
@@ -103,6 +114,7 @@
},
"r0": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -111,6 +123,7 @@
},
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -119,6 +132,7 @@
},
"r3": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -126,6 +140,7 @@
}
}
},
+
"ospf6": {
"router_id": "100.1.1.2",
"neighbors": {
@@ -146,6 +161,7 @@
},
"r1": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
@@ -154,6 +170,7 @@
},
"r2": {
"ipv6": "auto",
+
"ospf6": {
"area": "0.0.0.0",
"hello_interval": 1,
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py
index 47333fcb39..10c51a6784 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py
@@ -56,6 +56,7 @@ from lib.common_config import (
create_prefix_lists,
create_route_maps,
topo_daemons,
+ create_interfaces_cfg,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -747,6 +748,1084 @@ def test_ospfv3_type5_summary_tc42_p0(request):
write_test_footer(tc_name)
+def test_ospfv3_type5_summary_tc43_p0(request):
+ """OSPF summarisation with metric type 2."""
+ 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)
+
+ protocol = "ospf"
+
+ step(
+ "Configure 5 static routes from the same network on R0"
+ "5 static routes from different networks and redistribute in R0"
+ )
+ input_dict_static_rtes = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"], "next_hop": "blackhole"},
+ {"network": NETWORK2["ipv6"], "next_hop": "blackhole"},
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r0"
+ red_static(dut)
+
+ step("Verify that routes are learnt on R1.")
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_rib(tgen, "ipv6", dut, input_dict_static_rtes, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step(
+ "Configure External Route summary in R0 to summarise 5" " routes to one route."
+ )
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {"prefix": SUMMARY["ipv6"][0].split("/")[0], "mask": "32"}
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step(
+ "Verify that external routes are summarised to configured summary "
+ "address on R0 after 5 secs of delay timer expiry and only one "
+ "route is sent to R1."
+ )
+ input_dict_summary = {"r0": {"static_routes": [{"network": SUMMARY["ipv6"][0]}]}}
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Verify that show ip ospf summary should show the summaries.")
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 0,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step("Change the summary address mask to lower match (ex - 16 to 8)")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {"prefix": SUMMARY["ipv6"][0].split("/")[0], "mask": "16"},
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "delete": True,
+ },
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ sleep(5)
+
+ input_dict = {
+ "2011::/16": {
+ "Summary address": "2011::/16",
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 0,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step(
+ "Verify that external routes(static / connected) are summarised"
+ " to configured summary address with newly configured mask."
+ )
+
+ input_dict_summary = {"r0": {"static_routes": [{"network": "2011::0/16"}]}}
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Change the summary address mask to higher match (ex - 8 to 24)")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {"prefix": SUMMARY["ipv6"][0].split("/")[0], "mask": "32"}
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "2011::/32": {
+ "Summary address": "2011::/32",
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 0,
+ "External route count": 0,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step(
+ "Verify that external routes(static / connected) are summarised"
+ " to configured summary address with newly configured mask."
+ )
+ step("Configure 2 summary address with different mask of same network.")
+ step(
+ "Verify that external routes(static / connected) are summarised "
+ "to configured summary address with highest match."
+ )
+
+ input_dict_summary = {"r0": {"static_routes": [{"network": "2011::0/32"}]}}
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step(" Un configure one of the summary address.")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ sleep(5)
+
+ step(
+ "Verify that external routes(static / connected) are summarised"
+ " to configured summary address with newly configured mask."
+ )
+
+ input_dict_summary = {"r0": {"static_routes": [{"network": "2011::0/16"}]}}
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {"prefix": SUMMARY["ipv6"][0].split("/")[0], "mask": "16"}
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that external routes(static / connected) are summarised "
+ "to configured summary address with highest match."
+ )
+ input_dict_summary = {"r0": {"static_routes": [{"network": "2011::0/16"}]}}
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def ospfv3_type5_summary_tc45_p0(request):
+ """OSPF summarisation with Tag option"""
+ 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 on all the routers of the topology.")
+ reset_config_on_routers(tgen)
+
+ protocol = "ospf"
+
+ step(
+ "Configure 5 static routes from the same network on R0"
+ "5 static routes from different networks and redistribute in R0"
+ )
+ input_dict_static_rtes = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"], "next_hop": "blackhole"},
+ {"network": NETWORK2["ipv6"], "next_hop": "blackhole"},
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r0"
+ red_static(dut)
+
+ step("Verify that routes are learnt on R1.")
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_rib(tgen, "ipv6", dut, input_dict_static_rtes, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step(
+ "Configure External Route summary in R0 to summarise 5" " routes to one route."
+ )
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "tag": "1234",
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that external routes are summarised to configured summary"
+ " address on R0 and only one route is sent to R1 with configured tag."
+ )
+ input_dict_summary = {
+ "r0": {"static_routes": [{"network": SUMMARY["ipv6"][0], "tag": "1234"}]}
+ }
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Verify that show ip ospf summary should show the summaries with tag.")
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 1234,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step("Delete the configured summary")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "tag": "1234",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that summary lsa is withdrawn from R1 and deleted from R0.")
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv6", dut, input_dict_summary, protocol=protocol, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Summary Route still present in RIB".format(
+ tc_name
+ )
+
+ step("show ip ospf summary should not have any summary address.")
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 1234,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(
+ tgen, topo, dut, input_dict, ospf="ospf6", expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Summary still present in DB".format(tc_name)
+
+ step("Configure Min tag value")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {"prefix": SUMMARY["ipv6"][0].split("/")[0], "mask": "32", "tag": 1}
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ input_dict_summary = {
+ "r0": {"static_routes": [{"network": SUMMARY["ipv6"][0], "tag": "1"}]}
+ }
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Verify that show ip ospf summary should show the summaries with tag.")
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 1,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step("Configure Max Tag Value")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "tag": 4294967295,
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict_summary = {
+ "r0": {"static_routes": [{"network": SUMMARY["ipv6"][0], "tag": "4294967295"}]}
+ }
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step(
+ "Verify that boundary values tags are used for summary route"
+ " using show ip ospf route command."
+ )
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 4294967295,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step("configure new static route with different tag.")
+ input_dict_static_rtes_11 = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK_11["ipv6"], "next_hop": "blackhole", "tag": "88888"}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes_11)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("New tag has not been used by summary address.")
+
+ input_dict_summary = {
+ "r0": {"static_routes": [{"network": SUMMARY["ipv6"][0], "tag": "88888"}]}
+ }
+ dut = "r1"
+
+ result = verify_ospf6_rib(
+ tgen, dut, input_dict_summary, tag="88888", expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen,
+ "ipv6",
+ dut,
+ input_dict_summary,
+ protocol=protocol,
+ tag="88888",
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Routes still present in RIB".format(tc_name)
+
+ step(
+ "Verify that boundary values tags are used for summary route"
+ " using show ip ospf route command."
+ )
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 88888,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(
+ tgen, topo, dut, input_dict, ospf="ospf6", expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step("Delete the configured summary address")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "tag": 4294967295,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that 6 routes are advertised to neighbour with 5 routes"
+ " without any tag, 1 route with tag."
+ )
+
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_rib(tgen, "ipv6", dut, input_dict_static_rtes, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Verify that summary address is flushed from neighbor.")
+
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv6", dut, input_dict_summary, protocol=protocol, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Routes still present in RIB".format(tc_name)
+
+ step("Configure summary first & then configure matching static route.")
+
+ input_dict_static_rtes = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"], "next_hop": "blackhole", "delete": True},
+ {"network": NETWORK2["ipv6"], "next_hop": "blackhole", "delete": True},
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {"prefix": SUMMARY["ipv6"][0].split("/")[0], "mask": "32"}
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict_static_rtes = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"], "next_hop": "blackhole"},
+ {"network": NETWORK2["ipv6"], "next_hop": "blackhole"},
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Repeat steps 1 to 10 of summarisation in non Back bone area.")
+ reset_config_on_routers(tgen)
+
+ step("Change the area id on the interface on R0")
+ input_dict = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf6": {"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": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf6": {"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("Change the area id on the interface ")
+ input_dict = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf6": {"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 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf6": {"area": "0.0.0.1"},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ ospf_covergence = verify_ospf6_neighbor(tgen, topo)
+ assert ospf_covergence is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, ospf_covergence
+ )
+
+ step(
+ "Configure 5 static routes from the same network on R0"
+ "5 static routes from different networks and redistribute in R0"
+ )
+ input_dict_static_rtes = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"], "next_hop": "blackhole"},
+ {"network": NETWORK2["ipv6"], "next_hop": "blackhole"},
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r0"
+ red_static(dut)
+
+ step("Verify that routes are learnt on R1.")
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_rib(tgen, "ipv6", dut, input_dict_static_rtes, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step(
+ "Configure External Route summary in R0 to summarise 5" " routes to one route."
+ )
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "tag": "1234",
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that external routes are summarised to configured summary"
+ " address on R0 and only one route is sent to R1 with configured tag."
+ )
+ input_dict_summary = {
+ "r0": {"static_routes": [{"network": SUMMARY["ipv6"][0], "tag": "1234"}]}
+ }
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Verify that show ip ospf summary should show the summaries with tag.")
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 1234,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Delete the configured summary")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that summary lsa is withdrawn from R1 and deleted from R0.")
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv6", dut, input_dict_summary, protocol=protocol, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Summary Route still present in RIB".format(
+ tc_name
+ )
+
+ step("show ip ospf summary should not have any summary address.")
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 1234,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(
+ tgen, topo, dut, input_dict, ospf="ospf6", expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Summary still present in DB".format(tc_name)
+
+ step("Configure Min tag value")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {"prefix": SUMMARY["ipv6"][0].split("/")[0], "mask": "32", "tag": 1}
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ input_dict_summary = {
+ "r0": {"static_routes": [{"network": SUMMARY["ipv6"][0], "tag": "1"}]}
+ }
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Verify that show ip ospf summary should show the summaries with tag.")
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 1,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step("Configure Max Tag Value")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "tag": 4294967295,
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict_summary = {
+ "r0": {"static_routes": [{"network": SUMMARY["ipv6"][0], "tag": "4294967295"}]}
+ }
+ dut = "r1"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step(
+ "Verify that boundary values tags are used for summary route"
+ " using show ip ospf route command."
+ )
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 4294967295,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step("configure new static route with different tag.")
+ input_dict_static_rtes_11 = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK_11["ipv6"], "next_hop": "blackhole", "tag": "88888"}
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes_11)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("New tag has not been used by summary address.")
+
+ input_dict_summary = {
+ "r0": {"static_routes": [{"network": SUMMARY["ipv6"][0], "tag": "88888"}]}
+ }
+ dut = "r1"
+
+ result = verify_ospf6_rib(
+ tgen, dut, input_dict_summary, tag="88888", expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen,
+ "ipv6",
+ dut,
+ input_dict_summary,
+ protocol=protocol,
+ tag="88888",
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Routes still present in RIB".format(tc_name)
+
+ step(
+ "Verify that boundary values tags are used for summary route"
+ " using show ip ospf route command."
+ )
+ input_dict = {
+ SUMMARY["ipv6"][0]: {
+ "Summary address": SUMMARY["ipv6"][0],
+ "Metric-type": "E2",
+ "Metric": 20,
+ "Tag": 88888,
+ "External route count": 5,
+ }
+ }
+ dut = "r0"
+ result = verify_ospf_summary(
+ tgen, topo, dut, input_dict, ospf="ospf6", expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
+
+ step("Delete the configured summary address")
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {
+ "prefix": SUMMARY["ipv6"][0].split("/")[0],
+ "mask": "32",
+ "tag": 4294967295,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that 6 routes are advertised to neighbour with 5 routes"
+ " without any tag, 1 route with tag."
+ )
+
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ result = verify_rib(tgen, "ipv6", dut, input_dict_static_rtes, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Verify that summary address is flushed from neighbor.")
+
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict_summary, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv6", dut, input_dict_summary, protocol=protocol, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Routes still present in RIB".format(tc_name)
+
+ step("Configure summary first & then configure matching static route.")
+
+ input_dict_static_rtes = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"], "next_hop": "blackhole", "delete": True},
+ {"network": NETWORK2["ipv6"], "next_hop": "blackhole", "delete": True},
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ ospf_summ_r1 = {
+ "r0": {
+ "ospf6": {
+ "summary-address": [
+ {"prefix": SUMMARY["ipv6"][0].split("/")[0], "mask": "32"}
+ ]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_summ_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict_static_rtes = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"], "next_hop": "blackhole"},
+ {"network": NETWORK2["ipv6"], "next_hop": "blackhole"},
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_static_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
def test_ospfv3_type5_summary_tc46_p0(request):
"""OSPF summarisation with advertise and no advertise option"""
tc_name = request.node.name
@@ -1657,127 +2736,6 @@ def test_ospfv3_type5_summary_tc49_p2(request):
result is not True
), "Testcase {} : Failed" "Error: Routes still present in RIB".format(tc_name)
- step("Kill OSPF6d daemon on R0.")
- kill_router_daemons(tgen, "r0", ["ospf6d"])
-
- step("Bring up OSPF6d daemon on R0.")
- start_router_daemons(tgen, "r0", ["ospf6d"])
-
- step("Verify OSPF neighbors are up after bringing back ospf6d in R0")
- # Api call verify whether OSPF is converged
- ospf_covergence = verify_ospf6_neighbor(tgen, topo)
- assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
- ospf_covergence
- )
-
- step(
- "Verify that external routes are summarised to configured summary "
- "address on R0 after 5 secs of delay timer expiry and only one "
- "route is sent to R1."
- )
- input_dict_summary = {"r0": {"static_routes": [{"network": SUMMARY["ipv6"][0]}]}}
- dut = "r1"
-
- result = verify_ospf6_rib(tgen, dut, input_dict_summary)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
-
- result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
- assert (
- result is True
- ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
-
- step("Verify that show ip ospf summary should show the summaries.")
- input_dict = {
- SUMMARY["ipv6"][0]: {
- "Summary address": SUMMARY["ipv6"][0],
- "Metric-type": "E2",
- "Metric": 20,
- "Tag": 0,
- "External route count": 5,
- }
- }
- dut = "r0"
- result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
- assert (
- result is True
- ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
-
- step("Verify that originally advertised routes are withdraw from there" " peer.")
- input_dict = {
- "r0": {"static_routes": [{"network": NETWORK["ipv6"], "next_hop": "blackhole"}]}
- }
- dut = "r1"
- result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
- tc_name, result
- )
-
- result = verify_rib(
- tgen, "ipv6", dut, input_dict, protocol=protocol, expected=False
- )
- assert (
- result is not True
- ), "Testcase {} : Failed" "Error: Routes still present in RIB".format(tc_name)
-
- step("restart zebrad")
- kill_router_daemons(tgen, "r0", ["zebra"])
-
- step("Bring up zebra daemon on R0.")
- start_router_daemons(tgen, "r0", ["zebra"])
-
- step(
- "Verify that external routes are summarised to configured summary "
- "address on R0 after 5 secs of delay timer expiry and only one "
- "route is sent to R1."
- )
- input_dict_summary = {"r0": {"static_routes": [{"network": SUMMARY["ipv6"][0]}]}}
- dut = "r1"
-
- result = verify_ospf6_rib(tgen, dut, input_dict_summary)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
-
- result = verify_rib(tgen, "ipv6", dut, input_dict_summary, protocol=protocol)
- assert (
- result is True
- ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
-
- step("Verify that show ip ospf summary should show the summaries.")
- input_dict = {
- SUMMARY["ipv6"][0]: {
- "Summary address": SUMMARY["ipv6"][0],
- "Metric-type": "E2",
- "Metric": 20,
- "Tag": 0,
- "External route count": 5,
- }
- }
- dut = "r0"
- result = verify_ospf_summary(tgen, topo, dut, input_dict, ospf="ospf6")
- assert (
- result is True
- ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name)
-
- step("Verify that originally advertised routes are withdraw from there" " peer.")
- input_dict = {
- "r0": {"static_routes": [{"network": NETWORK["ipv6"], "next_hop": "blackhole"}]}
- }
- dut = "r1"
- result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: " "Routes still present in OSPF RIB {}".format(
- tc_name, result
- )
-
- result = verify_rib(
- tgen, "ipv6", dut, input_dict, protocol=protocol, expected=False
- )
- assert (
- result is not True
- ), "Testcase {} : Failed" "Error: Routes still present in RIB".format(tc_name)
-
write_test_footer(tc_name)
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py
new file mode 100644
index 0000000000..fe8be0a4b3
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py
@@ -0,0 +1,400 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2021 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
+from lib.topotest import frr_unicode
+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 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,
+ verify_rib,
+ create_static_routes,
+ step,
+ create_route_maps,
+ shutdown_bringup_interface,
+ create_interfaces_cfg,
+ topo_daemons,
+ get_frr_ipv6_linklocal,
+)
+from lib.topolog import logger
+from lib.topojson import build_config_from_json
+
+from lib.ospf import (
+ verify_ospf6_neighbor,
+ config_ospf_interface,
+ clear_ospf,
+ verify_ospf6_rib,
+ create_router_ospf,
+ verify_ospf6_interface,
+ verify_ospf6_database,
+ config_ospf6_interface,
+)
+
+from ipaddress import IPv6Address
+
+pytestmark = [pytest.mark.ospfd, pytest.mark.staticd]
+
+
+# Global variables
+topo = None
+
+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": ["2::1/128", "2::2/128", "2::3/128", "2::4/128", "2::5/128"],
+}
+MASK = {"ipv6": "32", "ipv6": "128"}
+
+"""
+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)
+
+ """
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ global topo, switch_name
+ 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...
+ json_file = "{}/ospfv3_ecmp_lan.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... 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_ospf6_neighbor(tgen, topo, lan=True)
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ switch_name = [k for k in topo["switches"].keys()][0]
+
+ 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
+
+ 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
+ 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: {"ospf6": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf6": {"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: {"ospf6": {"redistribute": [{"redist_type": "connected"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf6": {
+ "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)
+
+
+def get_llip(onrouter, intf):
+ """
+ API to get the link local ipv6 address of a perticular interface
+
+ Parameters
+ ----------
+ * `fromnode`: Source node
+ * `tonode` : interface for which link local ip needs to be returned.
+
+ Usage
+ -----
+ result = get_llip('r1', 'r2-link0')
+
+ Returns
+ -------
+ 1) link local ipv6 address from the interface.
+ 2) errormsg - when link local ip not found.
+ """
+ tgen = get_topogen()
+ intf = topo["routers"][onrouter]["links"][intf]["interface"]
+ llip = get_frr_ipv6_linklocal(tgen, onrouter, intf)
+ if llip:
+ logger.info("llip ipv6 address to be set as NH is %s", llip)
+ return llip
+ return None
+
+
+def get_glipv6(onrouter, intf):
+ """
+ API to get the global ipv6 address of a perticular interface
+
+ Parameters
+ ----------
+ * `onrouter`: Source node
+ * `intf` : interface for which link local ip needs to be returned.
+
+ Usage
+ -----
+ result = get_glipv6('r1', 'r2-link0')
+
+ Returns
+ -------
+ 1) global ipv6 address from the interface.
+ 2) errormsg - when link local ip not found.
+ """
+ glipv6 = (topo["routers"][onrouter]["links"][intf]["ipv6"]).split("/")[0]
+ if glipv6:
+ logger.info("Global ipv6 address to be set as NH is %s", glipv6)
+ return glipv6
+ return None
+
+
+# ##################################
+# Test cases start here.
+# ##################################
+
+
+def test_ospfv3_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_ospf6_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["ipv6"][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"]:
+ llip = get_llip(rtr, switch_name)
+ assert llip is not None, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ nh.append(llip)
+
+ llip = get_llip("r1", switch_name)
+ assert llip is not None, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ nh.remove(llip)
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ protocol = "ospf6"
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(" clear ip ospf interface on DUT(r0)")
+ clear_ospf(tgen, "r0", ospf="ospf6")
+
+ 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_ospf6_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_ospf6_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["ipv6"][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
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py
new file mode 100644
index 0000000000..dc3b915d49
--- /dev/null
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py
@@ -0,0 +1,482 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2021 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 copy import deepcopy
+import ipaddress
+from lib.ospf import (
+ verify_ospf6_neighbor,
+ config_ospf6_interface,
+ clear_ospf,
+ verify_ospf6_rib,
+ verify_ospf6_interface,
+ verify_ospf6_database,
+ create_router_ospf,
+)
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ clear_bgp_and_verify,
+ verify_bgp_rib,
+)
+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,
+ topo_daemons,
+ create_route_maps,
+ shutdown_bringup_interface,
+ create_interfaces_cfg,
+ check_router_status,
+)
+from ipaddress import IPv4Address
+from lib.topolog import logger
+from lib.topojson import build_config_from_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, "../"))
+
+pytestmark = [pytest.mark.ospfd, pytest.mark.staticd]
+
+# Global variables
+topo = None
+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": [
+ "2011:0:20::1/128",
+ "2011:0:20::2/128",
+ "2011:0:20::3/128",
+ "2011:0:20::4/128",
+ "2011:0:20::5/128",
+ ],
+}
+"""
+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.
+"""
+
+
+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...
+ json_file = "{}/ospfv3_nssa2.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... 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_ospf6_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():
+ """Teardown the pytest environment."""
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+
+def red_static(dut, config=True):
+ """Local def for Redstribute static routes inside ospf."""
+ global topo
+ tgen = get_topogen()
+ if config:
+ ospf_red = {dut: {"ospf6": {"redistribute": [{"redist_type": "static"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf6": {"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: {"ospf6": {"redistribute": [{"redist_type": "connected"}]}}}
+ else:
+ ospf_red = {
+ dut: {
+ "ospf6": {
+ "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_ospfv3_nssa_tc26_p0(request):
+ """Verify that ospf non back bone area can be configured as NSSA area"""
+ 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():
+ check_router_status(tgen)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ step("Configure ospf area 2 on r0 , r1 & r4, make the area 2 as NSSA area")
+
+ reset_config_on_routers(tgen)
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][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 = "ospf6"
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Un configure redistribute command in R4")
+ dut = "r2"
+ red_static(dut, config=False)
+
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 1, "routeType": "Network"}
+ ]
+ }
+ }
+
+ step("Configure area 0 on interface of r2 connecting to r1")
+
+ input_dict = {
+ "r2": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r2"]["links"]["r1"]["interface"],
+ "ospf6": {"area": "0.0.0.2"},
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r2": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r2"]["links"]["r1"]["interface"],
+ "ospf6": {"area": "0.0.0.0"},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("verify that ospf neighbor goes down between r2 and r1.")
+ result = verify_ospf6_neighbor(tgen, topo, dut="r2", expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Nbrs are not down" "Error: {}".format(tc_name, result)
+
+ step("Now configure area 0 on interface of r1 connecting to r2.")
+
+ input_dict = {
+ "r1": {
+ "links": {
+ "r2": {
+ "interface": topo["routers"]["r1"]["links"]["r2"]["interface"],
+ "ospf6": {"area": "0.0.0.2"},
+ "delete": True,
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r1": {
+ "links": {
+ "r2": {
+ "interface": topo["routers"]["r1"]["links"]["r2"]["interface"],
+ "ospf6": {"area": "0.0.0.0"},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that ospf neighbour comes up between r2 and r1.")
+ result = verify_ospf6_neighbor(tgen, topo, dut="r2")
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure area 2 on interface of r2 connecting to r1.")
+
+ input_dict = {
+ "r2": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r2"]["links"]["r1"]["interface"],
+ "ospf6": {"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 = {
+ "r2": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r2"]["links"]["r1"]["interface"],
+ "ospf6": {"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 ospf neighbor goes down between r2 and r1.")
+ result = verify_ospf6_neighbor(tgen, topo, dut="r2", expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Nbrs are not down" "Error: {}".format(tc_name, result)
+
+ step("Now configure area 2 on interface of r1 connecting to r2.")
+
+ input_dict = {
+ "r1": {
+ "links": {
+ "r2": {
+ "interface": topo["routers"]["r1"]["links"]["r2"]["interface"],
+ "ospf6": {"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 = {
+ "r1": {
+ "links": {
+ "r2": {
+ "interface": topo["routers"]["r1"]["links"]["r2"]["interface"],
+ "ospf6": {"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 ospf neighbour comes up between r2 and r1.")
+ result = verify_ospf6_neighbor(tgen, topo, dut="r2")
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+# As per internal discussion, this script has to be removed as translator
+# function is not supported, for more details kindly check this PR 2565570
+def ospfv3_nssa_tc27_p0(request):
+ """
+ OSPF NSSA.
+
+ Verify that ospf NSSA area DUT is capable receiving & processing
+ Type7 N2 route.
+ """
+ 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():
+ check_router_status(tgen)
+
+ global topo
+ step("Bring up the base config as per the topology")
+ step("Configure ospf area 2 on r0 , r1 & r4, make the area 2 as NSSA area")
+
+ reset_config_on_routers(tgen)
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][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 = "ospf6"
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Un configure redistribute command in R4")
+ dut = "r2"
+ red_static(dut, config=False)
+
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 1, "routeType": "Network"}
+ ]
+ }
+ }
+
+ dut = "r0"
+ result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv6", 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)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py
index 461efbe979..d7cf951c5f 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py
@@ -178,6 +178,312 @@ def teardown_module(mod):
# ##################################
+def test_ospfv3_routemaps_functionality_tc19_p0(request):
+ """
+ OSPF Route map - Verify OSPF route map support functionality.
+
+ """
+ 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["ipv6"][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)
+
+ ospf_red_r1 = {"r0": {"ospf6": {"redistribute": [{"redist_type": "static"}]}}}
+ result = create_router_ospf(tgen, topo, ospf_red_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r1"
+ lsid = NETWORK["ipv6"][0].split("/")[0]
+ rid = routerids[0]
+
+ protocol = "ospf"
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ ospf_red_r1 = {
+ "r0": {
+ "ospf6": {"redistribute": [{"redist_type": "static", "del_action": True}]}
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Create prefix-list in R0 to permit 10.0.20.1/32 prefix &" " deny 10.0.20.2/32"
+ )
+
+ # Create ip prefix list
+ pfx_list = {
+ "r0": {
+ "prefix_lists": {
+ "ipv6": {
+ "pf_list_1_ipv6": [
+ {
+ "seqid": 10,
+ "network": NETWORK["ipv6"][0],
+ "action": "permit",
+ },
+ {"seqid": 11, "network": "any", "action": "deny"},
+ ]
+ }
+ }
+ }
+ }
+ 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 creation failed. Error: {}".format(
+ tc_name, result
+ )
+
+ # Create route map
+ routemaps = {
+ "r0": {
+ "route_maps": {
+ "rmap_ipv6": [
+ {
+ "action": "permit",
+ "match": {"ipv6": {"prefix_lists": "pf_list_1_ipv6"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure route map rmap1 and redistribute static routes to"
+ " ospf using route map rmap1"
+ )
+
+ ospf_red_r1 = {
+ "r0": {
+ "ospf6": {
+ "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv6"}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ step("Verify that route map is activated in OSPF.")
+
+ step("Verify that route 10.0.20.1 is allowed and 10.0.20.2 is denied.")
+ dut = "r1"
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 1, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r1"
+ lsid = NETWORK["ipv6"][1].split("/")[0]
+ rid = routerids[0]
+
+ step("Change prefix rules to permit 10.0.20.2 and deny 10.0.20.1")
+ # Create ip prefix list
+ pfx_list = {
+ "r0": {
+ "prefix_lists": {
+ "ipv6": {
+ "pf_list_1_ipv6": [
+ {
+ "seqid": 10,
+ "network": NETWORK["ipv6"][1],
+ "action": "permit",
+ },
+ {"seqid": 11, "network": "any", "action": "deny"},
+ ]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, pfx_list)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that route 10.0.20.2 is allowed and 10.0.20.1 is denied.")
+ dut = "r1"
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][1], "no_of_ip": 1, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 1, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Route found in the RIB, Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv6", dut, input_dict, protocol=protocol, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Route found in the RIB, Error: {}".format(
+ tc_name, result
+ )
+
+ step("Delete and reconfigure prefix list.")
+ # Create ip prefix list
+ pfx_list = {
+ "r0": {
+ "prefix_lists": {
+ "ipv6": {
+ "pf_list_1_ipv6": [
+ {
+ "seqid": 10,
+ "network": NETWORK["ipv6"][1],
+ "action": "permit",
+ "delete": True,
+ },
+ {
+ "seqid": 11,
+ "network": "any",
+ "action": "deny",
+ "delete": True,
+ },
+ ]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, pfx_list)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_prefix_lists(tgen, pfx_list)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 5, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Route found in the RIB, Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv6", dut, input_dict, protocol=protocol, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Route found in the RIB, Error: {}".format(
+ tc_name, result
+ )
+
+ pfx_list = {
+ "r0": {
+ "prefix_lists": {
+ "ipv6": {
+ "pf_list_1_ipv6": [
+ {
+ "seqid": 10,
+ "network": NETWORK["ipv6"][1],
+ "action": "permit",
+ },
+ {"seqid": 11, "network": "any", "action": "deny"},
+ ]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, pfx_list)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that route 10.0.20.2 is allowed and 10.0.20.1 is denied.")
+ dut = "r1"
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][1], "no_of_ip": 1, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {"network": NETWORK["ipv6"][0], "no_of_ip": 1, "next_hop": "Null0"}
+ ]
+ }
+ }
+ result = verify_ospf6_rib(tgen, dut, input_dict, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Route found in the RIB, Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, "ipv6", dut, input_dict, protocol=protocol, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Route found in the RIB, Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
def test_ospfv3_routemaps_functionality_tc20_p0(request):
"""
OSPF route map support functionality.
@@ -461,7 +767,7 @@ def test_ospfv3_routemaps_functionality_tc22_p0(request):
{
"action": "permit",
"seq_id": "20",
- "match": {"ipv6": {"prefix_lists": "pf_list_2_ipv4"}},
+ "match": {"ipv6": {"prefix_lists": "pf_list_2_ipv6"}},
},
]
}
@@ -474,7 +780,7 @@ def test_ospfv3_routemaps_functionality_tc22_p0(request):
input_dict_2 = {
"r0": {
"prefix_lists": {
- "ipv4": {
+ "ipv6": {
"pf_list_1_ipv6": [
{"seqid": 10, "network": NETWORK["ipv6"][0], "action": "permit"}
]
@@ -489,8 +795,8 @@ def test_ospfv3_routemaps_functionality_tc22_p0(request):
input_dict_2 = {
"r0": {
"prefix_lists": {
- "ipv4": {
- "pf_list_2_ipv4": [
+ "ipv6": {
+ "pf_list_2_ipv6": [
{"seqid": 10, "network": NETWORK["ipv6"][1], "action": "permit"}
]
}
@@ -567,7 +873,7 @@ def test_ospfv3_routemaps_functionality_tc22_p0(request):
{
"action": "deny",
"seq_id": "20",
- "match": {"ipv6": {"prefix_lists": "pf_list_2_ipv4"}},
+ "match": {"ipv6": {"prefix_lists": "pf_list_2_ipv6"}},
}
]
}
@@ -624,6 +930,106 @@ def test_ospfv3_routemaps_functionality_tc22_p0(request):
write_test_footer(tc_name)
+def test_ospfv3_routemaps_functionality_tc23_p0(request):
+ """
+ OSPF Route map - Multiple set clauses.
+
+ Verify OSPF route map support functionality when we add/remove route-maps
+ with multiple set clauses and without any match statement.(Set 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["ipv6"][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)
+
+ ospf_red_r0 = {
+ "r0": {
+ "ospf6": {
+ "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv6"}]
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, ospf_red_r0)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure route map with set clause (set metric)")
+ # Create route map
+ routemaps = {
+ "r0": {
+ "route_maps": {
+ "rmap_ipv6": [
+ {"action": "permit", "seq_id": 10, "set": {"metric": 123}}
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, routemaps)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that configured metric is applied to ospf routes.")
+ dut = "r1"
+ protocol = "ospf"
+
+ result = verify_ospf6_rib(tgen, dut, input_dict, metric=123)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol, metric=123)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("un configure the set clause")
+ # Create route map
+ routemaps = {
+ "r0": {
+ "route_maps": {
+ "rmap_ipv6": [
+ {
+ "action": "permit",
+ "seq_id": 10,
+ "set": {"metric": 123, "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_ospf6_rib(tgen, dut, input_dict, metric=20)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ result = verify_rib(tgen, "ipv6", dut, input_dict, protocol=protocol, metric=20)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
def test_ospfv3_routemaps_functionality_tc24_p0(request):
"""
OSPF Route map - Multiple set clauses.
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py
index d8f659e5a9..21d03fadfb 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py
@@ -48,17 +48,21 @@ from lib.common_config import (
create_interfaces_cfg,
topo_daemons,
get_frr_ipv6_linklocal,
+ check_router_status,
+ create_static_routes,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
-
+from lib.bgp import create_router_bgp, verify_bgp_convergence
from lib.ospf import (
verify_ospf6_neighbor,
+ clear_ospf,
verify_ospf6_rib,
+ verify_ospf_database,
create_router_ospf,
- verify_ospf6_interface,
config_ospf6_interface,
+ verify_ospf6_interface,
)
@@ -251,6 +255,8 @@ def red_connected(dut, config=True):
# ##################################
# Test cases start here.
# ##################################
+
+
def test_ospfv3_redistribution_tc5_p0(request):
"""Test OSPF intra area route calculations."""
tc_name = request.node.name
@@ -259,7 +265,7 @@ def test_ospfv3_redistribution_tc5_p0(request):
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
+ check_router_status(tgen)
global topo
step("Bring up the base config.")
@@ -280,7 +286,11 @@ def test_ospfv3_redistribution_tc5_p0(request):
nh = llip
input_dict = {
- "r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]}
+ "r1": {
+ "static_routes": [
+ {"network": ip_net, "no_of_ip": 1, "routeType": "Network"}
+ ]
+ }
}
dut = "r1"
@@ -372,7 +382,7 @@ def test_ospfv3_redistribution_tc6_p0(request):
# Don't run this test if we have any failure.
if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
+ check_router_status(tgen)
global topo
step("Bring up the base config.")
@@ -380,8 +390,8 @@ def test_ospfv3_redistribution_tc6_p0(request):
step("Verify that OSPF neighbors are FULL.")
ospf_covergence = verify_ospf6_neighbor(tgen, topo)
- assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
- ospf_covergence
+ assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, ospf_covergence
)
step("verify intra area route is calculated for r0-r3 interface ip in R1")
@@ -391,7 +401,11 @@ def test_ospfv3_redistribution_tc6_p0(request):
assert llip is not None, "Testcase {} : Failed \n Error: {}".format(tc_name, llip)
nh = llip
input_dict = {
- "r1": {"static_routes": [{"network": ip_net, "no_of_ip": 1, "routeType": "N"}]}
+ "r1": {
+ "static_routes": [
+ {"network": ip_net, "no_of_ip": 1, "routeType": "Network"}
+ ]
+ }
}
dut = "r1"
@@ -460,9 +474,6 @@ def test_ospfv3_redistribution_tc6_p0(request):
intf = topo["routers"]["r0"]["links"]["r3"]["interface"]
shutdown_bringup_interface(tgen, dut, intf, False)
- step("Verify that intraroute calculated for R1 intf on R0 is deleted.")
- dut = "r1"
-
step("un shut the OSPF interface on R0")
dut = "r0"
shutdown_bringup_interface(tgen, dut, intf, True)
@@ -478,6 +489,168 @@ def test_ospfv3_redistribution_tc6_p0(request):
write_test_footer(tc_name)
+def test_ospfv3_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"
+ )
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ 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"]["ipv6"],
+ "no_of_ip": 1,
+ }
+ ]
+ }
+ }
+ for rtr in topo["routers"]:
+ result = verify_rib(tgen, "ipv6", 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": {"ipv6": {"unicast": {"neighbor": {}}}},
+ }
+ }
+ )
+ for node in topo["routers"]:
+ for rtr in topo["routers"]:
+ if node is not rtr:
+ topo["routers"][node]["bgp"]["address_family"]["ipv6"]["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)
+
+ # Modify router id
+ input_dict = {
+ "r0": {"bgp": {"router_id": "11.11.11.11"}},
+ "r1": {"bgp": {"router_id": "22.22.22.22"}},
+ "r2": {"bgp": {"router_id": "33.33.33.33"}},
+ "r3": {"bgp": {"router_id": "44.44.44.44"}},
+ }
+ result = create_router_bgp(tgen, topo, input_dict)
+ 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: {
+ "ospf6": {"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["ipv6"][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": {
+ "ipv6": {"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, "ipv6", 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_ospf6_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, "ipv6", rtr, input_dict, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
def test_ospfv3_cost_tc52_p0(request):
"""OSPF Cost - verifying ospf interface cost functionality"""
tc_name = request.node.name
@@ -485,6 +658,8 @@ def test_ospfv3_cost_tc52_p0(request):
tgen = get_topogen()
global topo
step("Bring up the base config.")
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
reset_config_on_routers(tgen)
step(
@@ -565,6 +740,184 @@ def test_ospfv3_cost_tc52_p0(request):
write_test_footer(tc_name)
+def test_ospfv3_def_rte_tc9_p0(request):
+ """OSPF default route - Verify OSPF default route origination."""
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ global topo
+ step("Bring up the base config.")
+ step("Configure OSPF on all the routers of the topology.")
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step(" Configure default-information originate always on R0.")
+ input_dict = {"r0": {"ospf6": {"default-information": {"originate": True}}}}
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r0"
+ step(" Configure default-information originate always on R0.")
+ input_dict = {
+ "r0": {
+ "ospf6": {
+ "default-information": {
+ "originate": True,
+ "always": True,
+ }
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that default route is originated in area always.")
+ dut = "r1"
+
+ step(" Configure default-information originate metric type 1 on R0.")
+ input_dict = {
+ "r0": {
+ "ospf6": {
+ "default-information": {
+ "originate": True,
+ "always": True,
+ "metric-type": 1,
+ }
+ }
+ }
+ }
+
+ step(
+ "Verify that default route is originated in area when external "
+ "routes are present in R0 with metric type as 1."
+ )
+ dut = "r0"
+ step(
+ "Verify that on R1 default route with type 1 is installed"
+ " (R1 is DUT in this case)"
+ )
+ dut = "r1"
+ step("Configure default-information originate metric type 2 on R0.")
+ input_dict = {
+ "r0": {
+ "ospf6": {
+ "default-information": {
+ "originate": True,
+ "always": True,
+ "metric-type": 2,
+ }
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that default route is originated in area when external"
+ " routes are present in R0 with metric type as 2."
+ )
+
+ dut = "r1"
+ step(" Configure default-information originate metric 100 on R0")
+ input_dict = {
+ "r0": {
+ "ospf6": {
+ "default-information": {
+ "originate": True,
+ "always": True,
+ "metric-type": 2,
+ "metric": 100,
+ }
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that default route is originated with cost as 100 on R0.")
+
+ dut = "r1"
+
+ step("Delete the default-information command")
+ input_dict = {
+ "r0": {
+ "ospf6": {
+ "default-information": {
+ "originate": True,
+ "always": True,
+ "delete": True,
+ }
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r0"
+ step("Configure default-information originate always on R0.")
+ input_dict = {
+ "r0": {
+ "ospf6": {
+ "default-information": {
+ "originate": True,
+ "always": True,
+ }
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure default route originate with active def route in zebra")
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": "0::0/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)
+
+ input_dict = {
+ "r0": {
+ "ospf6": {
+ "default-information": {
+ "originate": True,
+ }
+ }
+ }
+ }
+ result = create_router_ospf(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that default route is originated by R0.")
+ dut = "r1"
+
+ step("Delete static route")
+ input_dict = {
+ "r0": {
+ "static_routes": [
+ {
+ "network": "0::0/0",
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, 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))
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
index ed70c09fae..9ec06ec36b 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py
@@ -26,6 +26,8 @@ import os
import sys
import time
import pytest
+import ipaddress
+
from copy import deepcopy
from lib.topotest import frr_unicode
@@ -47,6 +49,8 @@ from lib.common_config import (
step,
create_interfaces_cfg,
topo_daemons,
+ create_debug_log_config,
+ apply_raw_config,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
@@ -55,6 +59,9 @@ from lib.ospf import (
verify_ospf6_neighbor,
clear_ospf,
verify_ospf6_interface,
+ create_router_ospf,
+ config_ospf6_interface,
+ verify_ospf6_rib,
)
from ipaddress import IPv6Address
@@ -381,6 +388,956 @@ def test_ospfv3_p2p_tc3_p0(request):
write_test_footer(tc_name)
+def test_ospfv3_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"],
+ "ospf6": {"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": {
+ "ospf6": {
+ "timerIntervalsConfigHello": 11,
+ "timerIntervalsConfigDead": 12,
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf6_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"],
+ "ospf6": {"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": {
+ "ospf6": {
+ "timerIntervalsConfigHello": 11,
+ "timerIntervalsConfigDead": 12,
+ }
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf6_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_ospf6_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"],
+ "ospf6": {"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"],
+ "ospf6": {"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": {
+ "ospf6": {
+ "timerIntervalsConfigHello": 10,
+ "timerIntervalsConfigDead": 40,
+ }
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf6_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_ospf6_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"],
+ "ospf6": {"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"],
+ "ospf6": {"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": {
+ "ospf6": {
+ "timerIntervalsConfigHello": 10,
+ "timerIntervalsConfigDead": 40,
+ }
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf6_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_ospf6_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"],
+ "ospf6": {"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"],
+ "ospf6": {"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": {
+ "ospf6": {
+ "timerIntervalsConfigHello": 1,
+ "timerIntervalsConfigDead": 4,
+ }
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf6_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_ospf6_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"],
+ "ospf6": {"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"],
+ "ospf6": {"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": {
+ "ospf6": {
+ "timerIntervalsConfigHello": 65535,
+ "timerIntervalsConfigDead": 4,
+ }
+ }
+ }
+ }
+ }
+ dut = "r0"
+ result = verify_ospf6_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_ospf6_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, ospf_covergence
+ )
+ step(" Try configuring timer values outside range for example 65536")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf6": {"hello_interval": 65536, "dead_interval": 4},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Create interface failed. 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"],
+ "ospf6": {"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": {"ospf6": {"timerIntervalsConfigHello": 10}}}}}
+ dut = "r1"
+ result = verify_ospf6_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_ospfv3_dead_tc11_p0(request):
+ """
+ OSPF timers.
+
+ Verify OSPF interface timer dead 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 dead interval from default value to some other value on r1")
+
+ topo1 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf6": {"hello_interval": 12, "dead_interval": 48},
+ }
+ }
+ }
+ }
+
+ 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": {"ospf6": {"timerIntervalsConfigDead": 48}}}}}
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("modify dead interval from default value to r1" "dead interval timer on r2")
+
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf6": {"dead_interval": 48, "hello_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": {"ospf6": {"timerIntervalsConfigDead": 48}}}}}
+ dut = "r0"
+ result = verify_ospf6_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_ospf6_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, ospf_covergence
+ )
+
+ step("remove ospf on R0")
+ ospf_del = {"r0": {"ospf6": {"delete": True}}}
+ result = create_router_ospf(tgen, topo, ospf_del)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ # reconfiguring deleted ospf process by resetting the configs.
+ reset_config_on_routers(tgen)
+
+ step("reconfigure the default dead interval timer value to " "default on r1 and r2")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf6": {"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"],
+ "ospf6": {"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": {"ospf6": {"timerIntervalsConfigDead": 40}}}}}
+ dut = "r0"
+ result = verify_ospf6_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_ospf6_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, ospf_covergence
+ )
+
+ step(" Configure dead timer = 65535 on r1 and r2")
+
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf6": {"dead_interval": 65535},
+ }
+ }
+ }
+ }
+
+ 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"],
+ "ospf6": {"dead_interval": 65535},
+ }
+ }
+ }
+ }
+
+ 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": {"ospf6": {"timerIntervalsConfigDead": 65535}}}}
+ }
+ dut = "r0"
+ result = verify_ospf6_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_ospf6_neighbor(tgen, topo, dut=dut)
+ assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, ospf_covergence
+ )
+
+ step(" Try configuring timer values outside range for example 65536")
+ topo1 = {
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf6": {"dead_interval": 65536},
+ }
+ }
+ }
+ }
+
+ result = create_interfaces_cfg(tgen, topo1)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Create interface config failed. Error: {}".format(
+ tc_name, result
+ )
+
+ step("Unconfigure the dead timer from the interface from r1 and r2.")
+
+ topo1 = {
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf6": {"dead_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": {"ospf6": {"timerIntervalsConfigDead": 40}}}}}
+ dut = "r1"
+ result = verify_ospf6_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_ospfv3_tc4_mtu_ignore_p0(request):
+ """
+ OSPF NFSM - MTU change
+
+ Verify NFSM events when ospf nbr changes with different MTU values
+ """
+ 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 on all the routers of the topology.")
+ step("Verify that OSPF neighbors are FULL.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Modify the MTU to non default Value on R0 to R1 interface. "
+ "Reset ospf neighbors on R0."
+ )
+
+ rtr0 = tgen.routers()["r0"]
+ rtr1 = tgen.routers()["r1"]
+
+ r0_r1_intf = topo["routers"]["r0"]["links"]["r1"]["interface"]
+ r1_r0_intf = topo["routers"]["r1"]["links"]["r0"]["interface"]
+
+ rtr0.run("ifconfig {} mtu 1400".format(r0_r1_intf))
+
+ clear_ospf(tgen, "r0", ospf="ospf6")
+ clear_ospf(tgen, "r1", ospf="ospf6")
+
+ step(
+ "Verify that OSPF neighborship between R0 and R1 is stuck in Exstart" " State."
+ )
+ result = verify_ospf6_neighbor(tgen, topo, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n OSPF nbrs are Full "
+ "instead of Exstart. Error: {}".format(tc_name, result)
+ )
+
+ step(
+ "Verify that configured MTU value is updated in the show ip " "ospf interface."
+ )
+
+ dut = "r0"
+ input_dict = {"r0": {"links": {"r1": {"ospf6": {"interfaceMtu": 1400}}}}}
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Modify the MTU to non default Value on R0 to R1 interface. "
+ "Reset ospf neighbors on R0."
+ )
+ rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf))
+
+ clear_ospf(tgen, "r0", ospf="ospf6")
+
+ step("Verify that OSPF neighborship between R0 and R1 becomes full.")
+ result = verify_ospf6_neighbor(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure mtu ignore and change the value of the mtu to non default"
+ " on R0 to R1 interface. Reset ospf neighbors on R0."
+ )
+ r0_ospf_mtu = {"r0": {"links": {"r1": {"ospf6": {"mtu_ignore": True}}}}}
+ result = config_ospf6_interface(tgen, topo, r0_ospf_mtu)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r0"
+ input_dict = {"r0": {"links": {"r1": {"ospf6": {"mtuMismatchDetection": True}}}}}
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ r1_ospf_mtu = {"r1": {"links": {"r0": {"ospf6": {"mtu_ignore": True}}}}}
+ result = config_ospf6_interface(tgen, topo, r1_ospf_mtu)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ rtr0.run("ifconfig {} mtu 1400".format(r0_r1_intf))
+
+ clear_ospf(tgen, "r0", ospf="ospf6")
+
+ step("Verify that OSPF neighborship between R0 and R1 becomes full.")
+ result = verify_ospf6_neighbor(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Unconfigure mtu-ignore command from the interface. "
+ "Reset ospf neighbors on R0."
+ )
+
+ r1_ospf_mtu = {
+ "r1": {"links": {"r0": {"ospf6": {"mtu_ignore": True, "delete": True}}}}
+ }
+ result = config_ospf6_interface(tgen, topo, r1_ospf_mtu)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ clear_ospf(tgen, "r0", ospf="ospf6")
+
+ step(
+ "Verify that OSPF neighborship between R0 and R1 is stuck in Exstart" " State."
+ )
+ result = verify_ospf6_neighbor(tgen, topo, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n OSPF nbrs are Full "
+ "instead of Exstart. Error: {}".format(tc_name, result)
+ )
+
+ step("Modify the MTU to again default valaue on R0 to R1 interface.")
+
+ rtr0.run("ifconfig {} mtu 1500".format(r0_r1_intf))
+
+ clear_ospf(tgen, "r0", ospf="ospf6")
+
+ step("Verify that OSPF neighborship between R0 and R1 becomes full.")
+ result = verify_ospf6_neighbor(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure ospf interface with jumbo MTU (9216)." "Reset ospf neighbors on R0."
+ )
+
+ rtr0.run("ifconfig {} mtu 9216".format(r0_r1_intf))
+ rtr1.run("ifconfig {} mtu 9216".format(r1_r0_intf))
+
+ clear_ospf(tgen, "r0", ospf="ospf6")
+ clear_ospf(tgen, "r1", ospf="ospf6")
+
+ step("Verify that OSPF neighborship between R0 and R1 becomes full.")
+ result = verify_ospf6_neighbor(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that jumbo MTU is updated in the show ip ospf interface.")
+ dut = "r0"
+ input_dict = {"r0": {"links": {"r1": {"ospf6": {"interfaceMtu": 9216}}}}}
+ result = verify_ospf6_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_ospfv3_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)
+
+ input_dict = {"r2": {"debug": {"log_file": "debug.log", "enable": ["ospf6"]}}}
+
+ result = create_debug_log_config(tgen, input_dict)
+
+ # Code coverage steps #Do Not upstream
+ input_dict_config = {
+ "r1": {
+ "raw_config": [
+ "end",
+ "debug ospf6 event",
+ "debug ospf6 gr helper",
+ "debug ospf6 ism events",
+ "debug ospf6 ism status",
+ "debug ospf6 ism timers",
+ "debug ospf6 nsm events",
+ "debug ospf6 nsm status",
+ "debug ospf6 nsm timers ",
+ "debug ospf6 nssa",
+ "debug ospf6 lsa aggregate",
+ "debug ospf6 lsa flooding ",
+ "debug ospf6 lsa generate",
+ "debug ospf6 lsa install ",
+ "debug ospf6 lsa refresh",
+ "debug ospf6 packet all detail",
+ "debug ospf6 packet all recv",
+ "debug ospf6 packet all send",
+ "debug ospf6 packet dd detail",
+ "debug ospf6 packet dd recv",
+ "debug ospf6 packet dd send ",
+ "debug ospf6 packet hello detail",
+ "debug ospf6 packet hello recv",
+ "debug ospf6 packet hello send",
+ "debug ospf6 packet ls-ack detail",
+ "debug ospf6 packet ls-ack recv",
+ "debug ospf6 packet ls-ack send",
+ "debug ospf6 packet ls-request detail",
+ "debug ospf6 packet ls-request recv",
+ "debug ospf6 packet ls-request send",
+ "debug ospf6 packet ls-update detail",
+ "debug ospf6 packet ls-update recv",
+ "debug ospf6 packet ls-update send",
+ "debug ospf6 sr",
+ "debug ospf6 te ",
+ "debug ospf6 zebra interface",
+ "debug ospf6 zebra redistribute",
+ ]
+ }
+ }
+
+ apply_raw_config(tgen, input_dict_config)
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr, ospf="ospf6")
+
+ step(" Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr, ospf="ospf6")
+
+ dut = "r1"
+ input_dict = {
+ "r1": {
+ "links": {
+ "r0": {
+ "ospf6": {
+ "status": "up",
+ "type": "BROADCAST",
+ "ospf6Enabled": True,
+ "attachedToArea": True,
+ "instanceId": 0,
+ "interfaceMtu": 1500,
+ "autoDetect": 1500,
+ "mtuMismatchDetection": "enabled",
+ "areaId": "0.0.0.0",
+ "cost": 10,
+ "transmitDelaySec": 1,
+ "priority": 1,
+ "timerIntervalsConfigHello": 1,
+ "timerIntervalsConfigDead": 4,
+ "timerIntervalsConfigRetransmit": 5,
+ "dr": "0.0.0.0",
+ "bdr": "0.0.0.0",
+ "numberOfInterfaceScopedLsa": 2,
+ "pendingLsaLsUpdateCount": 0,
+ "lsUpdateSendThread": "off",
+ "pendingLsaLsAckCount": 0,
+ "lsAckSendThread": "off",
+ }
+ }
+ }
+ }
+ }
+ result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ ip = topo["routers"]["r0"]["links"]["r3"]["ipv6"]
+ ip_net = str(ipaddress.ip_interface(u"{}".format(ip)).network)
+ nh = topo["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ input_dict = {
+ "r1": {
+ "static_routes": [
+ {"network": ip_net, "no_of_ip": 1, "routeType": "Network"}
+ ]
+ }
+ }
+
+ dut = "r1"
+ result = verify_ospf6_rib(tgen, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def ospfv3_router_id_tc14_p2(request):
+ """OSPF Router ID - Verify OSPF router id changes."""
+ 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("Configure system router id as 1.1.1.1 on R1 , clear ospf router")
+ ospf_rid = {"r0": {"ospf6": {"router_id": "1.1.1.1"}}}
+ result = create_router_ospf(tgen, topo, ospf_rid)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ step("configure ospf router id as 1.1.1.2 on R1, clear ospf router")
+ ospf_rid = {"r1": {"ospf6": {"router_id": "1.1.1.2"}}}
+ result = create_router_ospf(tgen, topo, ospf_rid)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ topo1 = deepcopy(topo)
+ step("Verify that OSPF takes system router ID as ospf router id.")
+
+ topo1["routers"]["r0"]["ospf6"]["router_id"] = "1.1.1.1"
+ topo1["routers"]["r1"]["ospf6"]["router_id"] = "1.1.1.2"
+
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr, ospf="ospf6")
+
+ ospf_covergence = verify_ospf6_neighbor(tgen, topo1)
+ assert ospf_covergence is True, "OSPF NBRs not up.Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(" delete ospf router id and clear ospf process.")
+ ospf_rid = {"r0": {"ospf6": {"del_router_id": "1.1.1.1"}}}
+ result = create_router_ospf(tgen, topo, ospf_rid)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ ospf_rid = {"r1": {"ospf6": {"del_router_id": "1.1.1.2"}}}
+ result = create_router_ospf(tgen, topo, ospf_rid)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ reset_config_on_routers(tgen)
+
+ step(" Configure R0 R1 R2 with same router ids")
+ ospf_rid = {"r0": {"ospf6": {"router_id": "1.1.1.1"}}}
+ result = create_router_ospf(tgen, topo, ospf_rid)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ step("configure ospf router id as 1.1.1.2 on R1, reboot router")
+ ospf_rid = {"r1": {"ospf6": {"router_id": "1.1.1.1"}}}
+ result = create_router_ospf(tgen, topo, ospf_rid)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ ospf_covergence = verify_ospf6_neighbor(tgen, topo, expected=False)
+ assert (
+ ospf_covergence is not True
+ ), "OSPF NBRs are up.Failed \n Error:" " {}".format(ospf_covergence)
+ topo1 = {}
+ topo1 = deepcopy(topo)
+
+ for rtr in ["r1", "r2", "r3", "r0"]:
+ topo1["routers"][rtr]["ospf6"].pop("router_id")
+
+ build_config_from_json(tgen, topo1, save_bkup=False)
+
+ ospf_covergence = verify_ospf6_neighbor(tgen, topo)
+ assert ospf_covergence is not True, (
+ "Testcase {} :Failed \n Neighborship "
+ "should not up as no router id is configured. Error: {}".format(tc_name, result)
+ )
+
+ step("Clear ospf process and check nbrs should not be up.")
+ for rtr in topo["routers"]:
+ clear_ospf(tgen, rtr, ospf="ospf6")
+
+ ospf_covergence = verify_ospf6_neighbor(tgen, topo)
+ assert ospf_covergence is not True, (
+ "Testcase {} :Failed \n Neighborship "
+ "should not up as no router id is configured. Error: {}".format(tc_name, result)
+ )
+
+ topo1 = deepcopy(topo)
+
+ step("Configure system router id on routers , clear ospf router")
+ ospf_rid = {
+ "r0": {"ospf6": {"router_id": "1.1.1.1"}},
+ "r1": {"ospf6": {"router_id": "1.1.1.2"}},
+ "r2": {"ospf6": {"router_id": "1.1.1.3"}},
+ "r3": {"ospf6": {"router_id": "1.1.1.4"}},
+ }
+ result = create_router_ospf(tgen, topo1, ospf_rid)
+ assert result is True, "Testcase : Failed \n Error: {}".format(result)
+
+ topo1["routers"]["r0"]["ospf6"]["router_id"] = "1.1.1.1"
+ topo1["routers"]["r1"]["ospf6"]["router_id"] = "1.1.1.2"
+ topo1["routers"]["r2"]["ospf6"]["router_id"] = "1.1.1.3"
+ topo1["routers"]["r3"]["ospf6"]["router_id"] = "1.1.1.4"
+
+ ospf_covergence = verify_ospf6_neighbor(tgen, topo1)
+ assert ospf_covergence is True, "OSPF NBRs not up.Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ step(" Bring up the base config as per the topology")
+ reset_config_on_routers(tgen)
+
+ ospf_covergence = verify_ospf6_neighbor(tgen, topo)
+ assert ospf_covergence is True, "OSPF NBRs not up.Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
+
+ write_test_footer(tc_name)
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py
index ae891d9067..b72691b71e 100644
--- a/tests/topotests/zebra_rib/test_zebra_rib.py
+++ b/tests/topotests/zebra_rib/test_zebra_rib.py
@@ -31,6 +31,7 @@ import sys
from functools import partial
import pytest
import json
+import platform
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -45,6 +46,20 @@ from time import sleep
pytestmark = [pytest.mark.sharpd]
+krel = platform.release()
+
+
+def config_macvlan(tgen, r_str, device, macvlan):
+ "Creates specified macvlan interace on physical device"
+
+ if topotest.version_cmp(krel, "5.1") < 0:
+ return
+
+ router = tgen.gears[r_str]
+ router.run(
+ "ip link add {} link {} type macvlan mode bridge".format(macvlan, device)
+ )
+ router.run("ip link set {} up".format(macvlan))
def setup_module(mod):
@@ -62,6 +77,8 @@ def setup_module(mod):
TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
)
+ # Macvlan interface for protodown func test */
+ config_macvlan(tgen, "r1", "r1-eth0", "r1-eth0-macvlan")
# Initialize all routers.
tgen.start_router()
@@ -269,6 +286,46 @@ def test_route_map_usage():
assert ok, result
+def test_protodown():
+ "Run protodown basic functionality test and report results."
+ pdown = False
+ count = 0
+ tgen = get_topogen()
+ if topotest.version_cmp(krel, "5.1") < 0:
+ tgen.errors = "kernel 5.1 needed for protodown tests"
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ # Set interface protodown on
+ r1.vtysh_cmd("sharp interface r1-eth0-macvlan protodown")
+
+ # Timeout to wait for dplane to handle it
+ while count < 10:
+ count += 1
+ output = r1.vtysh_cmd("show interface r1-eth0-macvlan")
+ if re.search(r"protodown reasons:.*sharp", output):
+ pdown = True
+ break
+ sleep(1)
+
+ assert pdown is True, "Interface r1-eth0-macvlan not set protodown"
+
+ # Set interface protodown off
+ r1.vtysh_cmd("no sharp interface r1-eth0-macvlan protodown")
+
+ # Timeout to wait for dplane to handle it
+ while count < 10:
+ count += 1
+ output = r1.vtysh_cmd("show interface r1-eth0-macvlan")
+ if not re.search(r"protodown reasons:.*sharp", output):
+ pdown = False
+ break
+ sleep(1)
+
+ assert pdown is False, "Interface r1-eth0-macvlan not set protodown off"
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()