summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/bgpd/test_aspath.c58
-rw-r--r--tests/topotests/bgp_aspath_zero/__init__.py0
-rw-r--r--tests/topotests/bgp_aspath_zero/exabgp.env53
-rw-r--r--tests/topotests/bgp_aspath_zero/peer1/exabgp.cfg17
-rw-r--r--tests/topotests/bgp_aspath_zero/r1/bgpd.conf6
-rw-r--r--tests/topotests/bgp_aspath_zero/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py121
-rw-r--r--tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py32
-rw-r--r--tests/topotests/bgp_community_alias/r1/bgpd.conf13
-rw-r--r--tests/topotests/bgp_community_alias/r2/bgpd.conf3
-rw-r--r--tests/topotests/bgp_community_alias/r2/zebra.conf1
-rw-r--r--tests/topotests/bgp_community_alias/test_bgp-community-alias.py44
-rw-r--r--tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf1
-rw-r--r--tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf1
-rw-r--r--tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf1
-rw-r--r--tests/topotests/bgp_default_route/r2/bgpd.conf3
-rw-r--r--tests/topotests/bgp_default_route/test_bgp_default-originate.py27
-rwxr-xr-xtests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py8
-rwxr-xr-xtests/topotests/conftest.py23
-rwxr-xr-xtests/topotests/docker/frr-topotests.sh10
-rw-r--r--tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json191
-rw-r--r--tests/topotests/lib/bgp.py412
-rw-r--r--tests/topotests/lib/common_config.py156
-rw-r--r--tests/topotests/lib/topogen.py4
-rw-r--r--tests/topotests/lib/topotest.py26
-rwxr-xr-xtests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py7
-rw-r--r--tests/topotests/ospf_gr_topo1/__init__.py0
-rw-r--r--tests/topotests/ospf_gr_topo1/rt1/ospfd.conf32
-rw-r--r--tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_database.json98
-rw-r--r--tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_neighbor.json11
-rw-r--r--tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_route.json180
-rw-r--r--tests/topotests/ospf_gr_topo1/rt1/show_ip_route.json210
-rw-r--r--tests/topotests/ospf_gr_topo1/rt1/zebra.conf23
-rw-r--r--tests/topotests/ospf_gr_topo1/rt2/ospfd.conf37
-rw-r--r--tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_database.json160
-rw-r--r--tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_neighbor.json18
-rw-r--r--tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_route.json201
-rw-r--r--tests/topotests/ospf_gr_topo1/rt2/show_ip_route.json224
-rw-r--r--tests/topotests/ospf_gr_topo1/rt2/zebra.conf23
-rw-r--r--tests/topotests/ospf_gr_topo1/rt3/ospfd.conf43
-rw-r--r--tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_database.json83
-rw-r--r--tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_neighbor.json25
-rw-r--r--tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_route.json214
-rw-r--r--tests/topotests/ospf_gr_topo1/rt3/show_ip_route.json223
-rw-r--r--tests/topotests/ospf_gr_topo1/rt3/zebra.conf26
-rw-r--r--tests/topotests/ospf_gr_topo1/rt4/ospfd.conf37
-rw-r--r--tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_database.json164
-rw-r--r--tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_neighbor.json18
-rw-r--r--tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_route.json202
-rw-r--r--tests/topotests/ospf_gr_topo1/rt4/show_ip_route.json224
-rw-r--r--tests/topotests/ospf_gr_topo1/rt4/zebra.conf23
-rw-r--r--tests/topotests/ospf_gr_topo1/rt5/ospfd.conf31
-rw-r--r--tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_database.json102
-rw-r--r--tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_neighbor.json11
-rw-r--r--tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_route.json203
-rw-r--r--tests/topotests/ospf_gr_topo1/rt5/show_ip_route.json225
-rw-r--r--tests/topotests/ospf_gr_topo1/rt5/zebra.conf20
-rw-r--r--tests/topotests/ospf_gr_topo1/rt6/ospfd.conf38
-rw-r--r--tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_database.json168
-rw-r--r--tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_neighbor.json18
-rw-r--r--tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_route.json214
-rw-r--r--tests/topotests/ospf_gr_topo1/rt6/show_ip_route.json224
-rw-r--r--tests/topotests/ospf_gr_topo1/rt6/zebra.conf23
-rw-r--r--tests/topotests/ospf_gr_topo1/rt7/ospfd.conf33
-rw-r--r--tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_database.json99
-rw-r--r--tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_neighbor.json11
-rw-r--r--tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_route.json168
-rw-r--r--tests/topotests/ospf_gr_topo1/rt7/show_ip_route.json210
-rw-r--r--tests/topotests/ospf_gr_topo1/rt7/zebra.conf23
-rwxr-xr-xtests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py393
70 files changed, 5608 insertions, 329 deletions
diff --git a/tests/bgpd/test_aspath.c b/tests/bgpd/test_aspath.c
index aaf3fd2aa4..c2d39752ab 100644
--- a/tests/bgpd/test_aspath.c
+++ b/tests/bgpd/test_aspath.c
@@ -469,7 +469,10 @@ static struct aspath_tests {
0,
0,
{
- COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 10,
+ COMMON_ATTRS,
+ BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 10,
},
COMMON_ATTR_SIZE + 3,
},
@@ -482,7 +485,10 @@ static struct aspath_tests {
-1,
0,
{
- COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 8,
+ COMMON_ATTRS,
+ BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 8,
},
COMMON_ATTR_SIZE + 3,
},
@@ -495,7 +501,10 @@ static struct aspath_tests {
-1,
0,
{
- COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 12,
+ COMMON_ATTRS,
+ BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 12,
},
COMMON_ATTR_SIZE + 3,
},
@@ -510,7 +519,8 @@ static struct aspath_tests {
{
COMMON_ATTRS,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_AS_PATH, 10,
+ BGP_ATTR_AS_PATH,
+ 10,
},
COMMON_ATTR_SIZE + 3,
},
@@ -525,7 +535,8 @@ static struct aspath_tests {
{
COMMON_ATTRS,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_AS4_PATH, 10,
+ BGP_ATTR_AS4_PATH,
+ 10,
},
COMMON_ATTR_SIZE + 3,
},
@@ -540,7 +551,8 @@ static struct aspath_tests {
{
COMMON_ATTRS,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_AS4_PATH, 10,
+ BGP_ATTR_AS4_PATH,
+ 10,
},
COMMON_ATTR_SIZE + 3,
},
@@ -553,7 +565,10 @@ static struct aspath_tests {
0,
PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV,
{
- COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 18,
+ COMMON_ATTRS,
+ BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 18,
},
COMMON_ATTR_SIZE + 3,
},
@@ -566,7 +581,10 @@ static struct aspath_tests {
-1,
PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV,
{
- COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 16,
+ COMMON_ATTRS,
+ BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 16,
},
COMMON_ATTR_SIZE + 3,
},
@@ -579,7 +597,10 @@ static struct aspath_tests {
-1,
PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV,
{
- COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 20,
+ COMMON_ATTRS,
+ BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 20,
},
COMMON_ATTR_SIZE + 3,
},
@@ -592,7 +613,10 @@ static struct aspath_tests {
-1,
PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV,
{
- COMMON_ATTRS, BGP_ATTR_FLAG_TRANS, BGP_ATTR_AS_PATH, 22,
+ COMMON_ATTRS,
+ BGP_ATTR_FLAG_TRANS,
+ BGP_ATTR_AS_PATH,
+ 22,
},
COMMON_ATTR_SIZE + 3,
},
@@ -607,7 +631,8 @@ static struct aspath_tests {
{
COMMON_ATTRS,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_AS_PATH, 18,
+ BGP_ATTR_AS_PATH,
+ 18,
},
COMMON_ATTR_SIZE + 3,
},
@@ -622,7 +647,8 @@ static struct aspath_tests {
{
COMMON_ATTRS,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_AS4_PATH, 14,
+ BGP_ATTR_AS4_PATH,
+ 14,
},
COMMON_ATTR_SIZE + 3,
},
@@ -637,7 +663,8 @@ static struct aspath_tests {
{
COMMON_ATTRS,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_AS4_PATH, 14,
+ BGP_ATTR_AS4_PATH,
+ 14,
},
COMMON_ATTR_SIZE + 3,
&test_segments[0],
@@ -648,12 +675,13 @@ static struct aspath_tests {
&test_segments[28],
"8466 3 52737 0 4096",
AS4_DATA,
- -1,
+ -2,
PEER_CAP_AS4_RCV | PEER_CAP_AS4_ADV,
{
COMMON_ATTRS,
BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL,
- BGP_ATTR_AS4_PATH, 22,
+ BGP_ATTR_AS4_PATH,
+ 22,
},
COMMON_ATTR_SIZE + 3,
},
diff --git a/tests/topotests/bgp_aspath_zero/__init__.py b/tests/topotests/bgp_aspath_zero/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_aspath_zero/__init__.py
diff --git a/tests/topotests/bgp_aspath_zero/exabgp.env b/tests/topotests/bgp_aspath_zero/exabgp.env
new file mode 100644
index 0000000000..28e642360a
--- /dev/null
+++ b/tests/topotests/bgp_aspath_zero/exabgp.env
@@ -0,0 +1,53 @@
+[exabgp.api]
+encoder = text
+highres = false
+respawn = false
+socket = ''
+
+[exabgp.bgp]
+openwait = 60
+
+[exabgp.cache]
+attributes = true
+nexthops = true
+
+[exabgp.daemon]
+daemonize = true
+pid = '/var/run/exabgp/exabgp.pid'
+user = 'exabgp'
+##daemonize = false
+
+[exabgp.log]
+all = false
+configuration = true
+daemon = true
+destination = '/var/log/exabgp.log'
+enable = true
+level = INFO
+message = false
+network = true
+packets = false
+parser = false
+processes = true
+reactor = true
+rib = false
+routes = false
+short = false
+timers = false
+
+[exabgp.pdb]
+enable = false
+
+[exabgp.profile]
+enable = false
+file = ''
+
+[exabgp.reactor]
+speed = 1.0
+
+[exabgp.tcp]
+acl = false
+bind = ''
+delay = 0
+once = false
+port = 179
diff --git a/tests/topotests/bgp_aspath_zero/peer1/exabgp.cfg b/tests/topotests/bgp_aspath_zero/peer1/exabgp.cfg
new file mode 100644
index 0000000000..fe9ea01eca
--- /dev/null
+++ b/tests/topotests/bgp_aspath_zero/peer1/exabgp.cfg
@@ -0,0 +1,17 @@
+neighbor 10.0.0.1 {
+ router-id 10.0.0.2;
+ local-address 10.0.0.2;
+ local-as 65001;
+ peer-as 65534;
+
+ static {
+ route 192.168.100.101/32 {
+ next-hop 10.0.0.2;
+ }
+
+ route 192.168.100.102/32 {
+ as-path [65000 0 65001];
+ next-hop 10.0.0.2;
+ }
+ }
+}
diff --git a/tests/topotests/bgp_aspath_zero/r1/bgpd.conf b/tests/topotests/bgp_aspath_zero/r1/bgpd.conf
new file mode 100644
index 0000000000..002a5c78c0
--- /dev/null
+++ b/tests/topotests/bgp_aspath_zero/r1/bgpd.conf
@@ -0,0 +1,6 @@
+!
+router bgp 65534
+ no bgp ebgp-requires-policy
+ neighbor 10.0.0.2 remote-as external
+ neighbor 10.0.0.2 timers 3 10
+!
diff --git a/tests/topotests/bgp_aspath_zero/r1/zebra.conf b/tests/topotests/bgp_aspath_zero/r1/zebra.conf
new file mode 100644
index 0000000000..22a26ac610
--- /dev/null
+++ b/tests/topotests/bgp_aspath_zero/r1/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r1-eth0
+ ip address 10.0.0.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py
new file mode 100644
index 0000000000..903ab12a13
--- /dev/null
+++ b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# 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.
+#
+
+"""
+Test if BGP UPDATE with AS-PATH attribute with value zero (0)
+is threated as withdrawal.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from mininet.topo import Topo
+
+pytestmark = [pytest.mark.bgpd]
+
+
+class BgpAggregatorAsnZero(Topo):
+ def build(self, *_args, **_opts):
+ tgen = get_topogen(self)
+
+ r1 = tgen.add_router("r1")
+ peer1 = tgen.add_exabgp_peer(
+ "peer1", ip="10.0.0.2", defaultRoute="via 10.0.0.1"
+ )
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(r1)
+ switch.add_link(peer1)
+
+
+def setup_module(mod):
+ tgen = Topogen(BgpAggregatorAsnZero, mod.__name__)
+ tgen.start_topology()
+
+ router = tgen.gears["r1"]
+ router.load_config(TopoRouter.RD_ZEBRA, os.path.join(CWD, "r1/zebra.conf"))
+ router.load_config(TopoRouter.RD_BGP, os.path.join(CWD, "r1/bgpd.conf"))
+ router.start()
+
+ peer = tgen.gears["peer1"]
+ peer.start(os.path.join(CWD, "peer1"), os.path.join(CWD, "exabgp.env"))
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_aggregator_zero():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_converge():
+ output = json.loads(
+ tgen.gears["r1"].vtysh_cmd("show ip bgp neighbor 10.0.0.2 json")
+ )
+ expected = {
+ "10.0.0.2": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 1}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "More than one prefix seen at r1, SHOULD be only one."
+
+ def _bgp_has_correct_routes_without_asn_0():
+ output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp json"))
+ expected = {"routes": {"192.168.100.101/32": [{"valid": True}]}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_has_correct_routes_without_asn_0)
+ success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed listing 192.168.100.101/32, SHOULD be accepted."
+
+
+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/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
index 374cce21f6..485a76c6b2 100644
--- a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
+++ b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
@@ -774,9 +774,9 @@ def test_BGP_attributes_with_vrf_default_keyword_p0(request):
}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict)
- assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_rib(tgen, addr_type, dut, input_dict)
- assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
for addr_type in ADDR_TYPES:
dut = "r4"
@@ -793,9 +793,9 @@ def test_BGP_attributes_with_vrf_default_keyword_p0(request):
}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict)
- assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_rib(tgen, addr_type, dut, input_dict)
- assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
input_dict_4 = {"largeCommunity": "500:500:500", "community": "500:500"}
@@ -1134,15 +1134,10 @@ def test_bgp_with_loopback_with_same_subnet_p1(request):
dut = "r1"
protocol = "bgp"
for addr_type in ADDR_TYPES:
- result = verify_rib(tgen, addr_type, dut, input_dict_r1, protocol=protocol)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(
- tc_name, result
- )
-
- result = verify_fib_routes(tgen, addr_type, dut, input_dict_r1, expected=False)
- assert result is not True, "Testcase {} : Failed \n"
+ result = verify_fib_routes(tgen, addr_type, dut, input_dict_r1)
+ assert result is not True, "Testcase {} : Failed \n".format(tc_name)
"Expected behavior: routes should not present in fib \n"
- "Error: {}".format(tc_name, result)
+ "Error: {}".format(result)
step("Verify Ipv4 and Ipv6 network installed in r3 RIB but not in FIB")
input_dict_r3 = {
@@ -1156,17 +1151,10 @@ def test_bgp_with_loopback_with_same_subnet_p1(request):
dut = "r3"
protocol = "bgp"
for addr_type in ADDR_TYPES:
- result = verify_rib(
- tgen, addr_type, dut, input_dict_r3, protocol=protocol, fib=None
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(
- tc_name, result
- )
-
- result = verify_fib_routes(tgen, addr_type, dut, input_dict_r1, expected=False)
- assert result is not True, "Testcase {} : Failed \n"
+ result = verify_fib_routes(tgen, addr_type, dut, input_dict_r1)
+ assert result is not True, "Testcase {} : Failed \n".format(tc_name)
"Expected behavior: routes should not present in fib \n"
- "Error: {}".format(tc_name, result)
+ "Error: {}".format(result)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_community_alias/r1/bgpd.conf b/tests/topotests/bgp_community_alias/r1/bgpd.conf
index 06113bdd2a..a6366204e8 100644
--- a/tests/topotests/bgp_community_alias/r1/bgpd.conf
+++ b/tests/topotests/bgp_community_alias/r1/bgpd.conf
@@ -6,4 +6,17 @@ bgp community alias 65001:1:1 large-community-r2-1
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.1.2 remote-as external
+ address-family ipv4 unicast
+ redistribute connected
+ neighbor 192.168.1.2 route-map r2 in
+ exit-address-family
+!
+route-map r2 permit 10
+ match alias community-r2-1
+ set tag 10
+route-map r2 permit 20
+ match alias community-r2-2
+ set tag 20
+route-map r2 permit 30
+ set tag 100
!
diff --git a/tests/topotests/bgp_community_alias/r2/bgpd.conf b/tests/topotests/bgp_community_alias/r2/bgpd.conf
index fc67ff2ad2..9276fe592d 100644
--- a/tests/topotests/bgp_community_alias/r2/bgpd.conf
+++ b/tests/topotests/bgp_community_alias/r2/bgpd.conf
@@ -8,6 +8,7 @@ router bgp 65002
!
ip prefix-list p1 permit 172.16.16.1/32
ip prefix-list p2 permit 172.16.16.2/32
+ip prefix-list p3 permit 172.16.16.3/32
!
route-map r1 permit 10
match ip address prefix-list p1
@@ -16,4 +17,6 @@ route-map r1 permit 10
route-map r1 permit 20
match ip address prefix-list p2
set community 65002:1 65002:2
+route-map r1 permit 30
+ match ip address prefix-list p3
!
diff --git a/tests/topotests/bgp_community_alias/r2/zebra.conf b/tests/topotests/bgp_community_alias/r2/zebra.conf
index a806628a8e..b8cb9baf3c 100644
--- a/tests/topotests/bgp_community_alias/r2/zebra.conf
+++ b/tests/topotests/bgp_community_alias/r2/zebra.conf
@@ -2,6 +2,7 @@
int lo
ip address 172.16.16.1/32
ip address 172.16.16.2/32
+ ip address 172.16.16.3/32
!
int r2-eth0
ip address 192.168.1.2/24
diff --git a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py
index 90eeaaa731..c41ba810f1 100644
--- a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py
+++ b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py
@@ -84,39 +84,57 @@ def test_bgp_community_alias():
router = tgen.gears["r1"]
def _bgp_converge(router):
- output = json.loads(
- router.vtysh_cmd("show bgp ipv4 unicast 172.16.16.1/32 json")
- )
+ output = json.loads(router.vtysh_cmd("show ip route json"))
expected = {
- "paths": [
+ "172.16.16.1/32": [
+ {
+ "tag": 10,
+ "communities": "community-r2-1 65001:2",
+ "largeCommunities": "large-community-r2-1 65001:1:2",
+ }
+ ],
+ "172.16.16.2/32": [
+ {
+ "tag": 20,
+ "communities": "65002:1 community-r2-2",
+ "largeCommunities": "",
+ }
+ ],
+ "172.16.16.3/32": [
{
- "community": {"string": "community-r2-1 65001:2"},
- "largeCommunity": {"string": "large-community-r2-1 65001:1:2"},
+ "tag": 100,
+ "communities": "",
+ "largeCommunities": "",
}
- ]
+ ],
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_converge, router)
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
- assert result is None, 'Cannot see BGP community aliases "{}"'.format(router)
+ assert result is None, "Cannot see BGP community aliases at r1"
def _bgp_show_prefixes_by_alias(router):
output = json.loads(
- router.vtysh_cmd("show bgp ipv4 unicast alias community-r2-2 json detail")
+ router.vtysh_cmd(
+ "show bgp ipv4 unicast alias large-community-r2-1 json detail"
+ )
)
expected = {
"routes": {
- "172.16.16.2/32": [{"community": {"string": "65002:1 community-r2-2"}}]
+ "172.16.16.1/32": [
+ {
+ "community": {"string": "community-r2-1 65001:2"},
+ "largeCommunity": {"string": "large-community-r2-1 65001:1:2"},
+ }
+ ]
}
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_show_prefixes_by_alias, router)
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
- assert result is None, 'Cannot see BGP prefixes by community alias "{}"'.format(
- router
- )
+ assert result is None, "Cannot see BGP prefixes by community alias at r1"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf
index 633d1832fd..293b38c7e8 100644
--- a/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf
+++ b/tests/topotests/bgp_conditional_advertisement/r1/bgpd.conf
@@ -17,6 +17,7 @@ route-map DEF permit 10
!
router bgp 1
bgp log-neighbor-changes
+ bgp conditional-advertisement timer 5
no bgp ebgp-requires-policy
neighbor 10.10.10.2 remote-as 2
!
diff --git a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf
index c6147fe658..82525fac64 100644
--- a/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf
+++ b/tests/topotests/bgp_conditional_advertisement/r2/bgpd.conf
@@ -32,6 +32,7 @@ route-map RMAP-2 deny 10
!
router bgp 2
bgp log-neighbor-changes
+ bgp conditional-advertisement timer 5
no bgp ebgp-requires-policy
neighbor 10.10.10.1 remote-as 1
neighbor 10.10.20.3 remote-as 3
diff --git a/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf b/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf
index 2f4f5068d8..f389f309a6 100644
--- a/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf
+++ b/tests/topotests/bgp_conditional_advertisement/r3/bgpd.conf
@@ -1,6 +1,7 @@
!
router bgp 3
bgp log-neighbor-changes
+ bgp conditional-advertisement timer 5
no bgp ebgp-requires-policy
neighbor 10.10.20.2 remote-as 2
!
diff --git a/tests/topotests/bgp_default_route/r2/bgpd.conf b/tests/topotests/bgp_default_route/r2/bgpd.conf
index 00c96cc58b..6d1080c119 100644
--- a/tests/topotests/bgp_default_route/r2/bgpd.conf
+++ b/tests/topotests/bgp_default_route/r2/bgpd.conf
@@ -2,7 +2,4 @@ router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.255.1 remote-as 65000
neighbor 192.168.255.1 timers 3 10
- address-family ipv4 unicast
- redistribute connected
- exit-address-family
!
diff --git a/tests/topotests/bgp_default_route/test_bgp_default-originate.py b/tests/topotests/bgp_default_route/test_bgp_default-originate.py
index d8de0f0ac6..19632162b4 100644
--- a/tests/topotests/bgp_default_route/test_bgp_default-originate.py
+++ b/tests/topotests/bgp_default_route/test_bgp_default-originate.py
@@ -79,10 +79,10 @@ def test_bgp_default_originate_route_map():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- router = tgen.gears["r2"]
-
- def _bgp_converge(router):
- output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ def _bgp_check_if_received():
+ output = json.loads(
+ tgen.gears["r2"].vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")
+ )
expected = {
"192.168.255.1": {
"bgpState": "Established",
@@ -91,22 +91,27 @@ def test_bgp_default_originate_route_map():
}
return topotest.json_cmp(output, expected)
+ def _bgp_check_if_originated():
+ output = json.loads(tgen.gears["r1"].vtysh_cmd("show ip bgp summary json"))
+ expected = {"ipv4Unicast": {"peers": {"192.168.255.2": {"pfxSnt": 1}}}}
+ return topotest.json_cmp(output, expected)
+
def _bgp_default_route_is_valid(router):
output = json.loads(router.vtysh_cmd("show ip bgp 0.0.0.0/0 json"))
expected = {"paths": [{"valid": True}]}
return topotest.json_cmp(output, expected)
- test_func = functools.partial(_bgp_converge, router)
+ test_func = functools.partial(_bgp_check_if_received)
success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "No 0.0.0.0/0 at r2 from r1"
- assert result is None, 'Failed to see bgp convergence in "{}"'.format(router)
-
- test_func = functools.partial(_bgp_default_route_is_valid, router)
+ test_func = functools.partial(_bgp_check_if_originated)
success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "No 0.0.0.0/0 from r1 to r2"
- assert (
- result is None
- ), 'Failed to see applied metric for default route in "{}"'.format(router)
+ test_func = functools.partial(_bgp_default_route_is_valid, tgen.gears["r2"])
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed to see 0.0.0.0/0 in r2"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py b/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py
index 086bad6481..fd5bb38b98 100755
--- a/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py
+++ b/tests/topotests/bgp_evpn_vxlan_topo1/test_bgp_evpn_vxlan.py
@@ -365,6 +365,10 @@ def test_ip_pe1_learn():
"run the IP learn test for PE1"
tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
host1 = tgen.gears["host1"]
pe1 = tgen.gears["PE1"]
pe2 = tgen.gears["PE2"]
@@ -380,6 +384,10 @@ def test_ip_pe2_learn():
"run the IP learn test for PE2"
tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
host2 = tgen.gears["host2"]
pe1 = tgen.gears["PE1"]
pe2 = tgen.gears["PE2"]
diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py
index e57db7471c..d119b0931b 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -26,6 +26,12 @@ def pytest_addoption(parser):
only run the setup_module() to setup the topology without running any tests.
"""
parser.addoption(
+ "--asan-abort",
+ action="store_true",
+ help="Configure address sanitizer to abort process on error",
+ )
+
+ parser.addoption(
"--gdb-breakpoints",
metavar="SYMBOL[,SYMBOL...]",
help="Comma-separated list of functions to set gdb breakpoints on",
@@ -68,6 +74,12 @@ def pytest_addoption(parser):
)
parser.addoption(
+ "--strace-daemons",
+ metavar="DAEMON[,DAEMON...]",
+ help="Comma-separated list of daemons to strace, or 'all'",
+ )
+
+ parser.addoption(
"--topology-only",
action="store_true",
default=False,
@@ -167,6 +179,9 @@ def pytest_configure(config):
if not diagnose_env():
pytest.exit("environment has errors, please read the logs")
+ asan_abort = config.getoption("--asan-abort")
+ topotest_extra_config["asan_abort"] = asan_abort
+
gdb_routers = config.getoption("--gdb-routers")
gdb_routers = gdb_routers.split(",") if gdb_routers else []
topotest_extra_config["gdb_routers"] = gdb_routers
@@ -185,6 +200,9 @@ def pytest_configure(config):
shell = config.getoption("--shell")
topotest_extra_config["shell"] = shell.split(",") if shell else []
+ strace = config.getoption("--strace-daemons")
+ topotest_extra_config["strace_daemons"] = strace.split(",") if strace else []
+
pause_after = config.getoption("--pause-after")
shell_on_error = config.getoption("--shell-on-error")
@@ -244,6 +262,11 @@ def pytest_runtest_makereport(item, call):
)
)
+ # We want to pause, if requested, on any error not just test cases
+ # (e.g., call.when == "setup")
+ if not pause:
+ pause = topotest_extra_config["pause_after"]
+
# (topogen) Set topology error to avoid advancing in the test.
tgen = get_topogen()
if tgen is not None:
diff --git a/tests/topotests/docker/frr-topotests.sh b/tests/topotests/docker/frr-topotests.sh
index 9ef59b3bbc..1eaaea2971 100755
--- a/tests/topotests/docker/frr-topotests.sh
+++ b/tests/topotests/docker/frr-topotests.sh
@@ -145,7 +145,15 @@ if [ "${TOPOTEST_PULL:-1}" = "1" ]; then
docker pull frrouting/topotests:latest
fi
+if [[ -n "$TMUX" ]]; then
+ TMUX_OPTIONS="-v $(dirname $TMUX):$(dirname $TMUX) -e TMUX=$TMUX -e TMUX_PANE=$TMUX_PANE"
+fi
+
+if [[ -n "$STY" ]]; then
+ SCREEN_OPTIONS="-v /run/screen:/run/screen -e STY=$STY"
+fi
set -- --rm -i \
+ -v "$HOME:$HOME:ro" \
-v "$TOPOTEST_LOGS:/tmp" \
-v "$TOPOTEST_FRR:/root/host-frr:ro" \
-v "$TOPOTEST_BUILDCACHE:/root/persist" \
@@ -154,6 +162,8 @@ set -- --rm -i \
-e "TOPOTEST_DOC=$TOPOTEST_DOC" \
-e "TOPOTEST_SANITIZER=$TOPOTEST_SANITIZER" \
--privileged \
+ $SCREEN_OPTINS \
+ $TMUX_OPTIONS \
$TOPOTEST_OPTIONS \
frrouting/topotests:latest "$@"
diff --git a/tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json b/tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json
index 14842da326..dd412708bb 100644
--- a/tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json
+++ b/tests/topotests/evpn_type5_test_topo1/evpn_type5_topo1.json
@@ -41,7 +41,10 @@
"neighbor": {
"e1": {
"dest_link": {
- "r1": {}
+ "r1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -55,7 +58,10 @@
"neighbor": {
"e1": {
"dest_link": {
- "r1": {}
+ "r1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -106,7 +112,10 @@
"neighbor": {
"e1": {
"dest_link": {
- "r2-link1": {}
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -120,7 +129,10 @@
"neighbor": {
"e1": {
"dest_link": {
- "r2-link1": {}
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -140,7 +152,10 @@
"neighbor": {
"e1": {
"dest_link": {
- "r2-link2": {}
+ "r2-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -154,7 +169,10 @@
"neighbor": {
"e1": {
"dest_link": {
- "r2-link2": {}
+ "r2-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -222,7 +240,10 @@
"neighbor": {
"r1": {
"dest_link": {
- "e1": {}
+ "e1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -233,7 +254,10 @@
"neighbor": {
"r1": {
"dest_link": {
- "e1": {}
+ "e1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -262,7 +286,10 @@
"neighbor": {
"r2": {
"dest_link": {
- "e1-link1": {}
+ "e1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -273,7 +300,10 @@
"neighbor": {
"r2": {
"dest_link": {
- "e1-link1": {}
+ "e1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -302,7 +332,10 @@
"neighbor": {
"r2": {
"dest_link": {
- "e1-link2": {}
+ "e1-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -313,7 +346,10 @@
"neighbor": {
"r2": {
"dest_link": {
- "e1-link2": {}
+ "e1-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -342,6 +378,8 @@
"d1": {
"dest_link": {
"e1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
"deactivate": "ipv4"
}
}
@@ -349,6 +387,8 @@
"d2": {
"dest_link": {
"e1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
"deactivate": "ipv4"
}
}
@@ -412,6 +452,8 @@
"e1": {
"dest_link": {
"d1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
"deactivate": "ipv4"
}
}
@@ -442,7 +484,10 @@
"neighbor": {
"r3": {
"dest_link": {
- "d1": {}
+ "d1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -453,7 +498,10 @@
"neighbor": {
"r3": {
"dest_link": {
- "d1": {}
+ "d1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -482,7 +530,10 @@
"neighbor": {
"r4": {
"dest_link": {
- "d1-link1": {}
+ "d1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -493,7 +544,10 @@
"neighbor": {
"r4": {
"dest_link": {
- "d1-link1": {}
+ "d1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -522,7 +576,10 @@
"neighbor": {
"r4": {
"dest_link": {
- "d1-link2": {}
+ "d1-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -533,7 +590,10 @@
"neighbor": {
"r4": {
"dest_link": {
- "d1-link2": {}
+ "d1-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -590,7 +650,9 @@
"e1": {
"dest_link": {
"d2-link1": {
- "deactivate": "ipv4"
+ "deactivate": "ipv4",
+ "keepalivetimer": 1,
+ "holddowntimer": 3
}
}
}
@@ -620,7 +682,10 @@
"neighbor": {
"r3": {
"dest_link": {
- "d2": {}
+ "d2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -631,7 +696,10 @@
"neighbor": {
"r3": {
"dest_link": {
- "d2": {}
+ "d2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -660,7 +728,10 @@
"neighbor": {
"r4": {
"dest_link": {
- "d2-link1": {}
+ "d2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -671,7 +742,10 @@
"neighbor": {
"r4": {
"dest_link": {
- "d2-link1": {}
+ "d2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -700,7 +774,10 @@
"neighbor": {
"r4": {
"dest_link": {
- "d2-link2": {}
+ "d2-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -711,7 +788,10 @@
"neighbor": {
"r4": {
"dest_link": {
- "d2-link2": {}
+ "d2-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -755,12 +835,18 @@
"neighbor": {
"d1": {
"dest_link": {
- "r3": {}
+ "r3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
},
"d2": {
"dest_link": {
- "r3": {}
+ "r3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -771,12 +857,18 @@
"neighbor": {
"d1": {
"dest_link": {
- "r3": {}
+ "r3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
},
"d2": {
"dest_link": {
- "r3": {}
+ "r3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -814,12 +906,18 @@
"neighbor": {
"d1": {
"dest_link": {
- "r4-link1": {}
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
},
"d2": {
"dest_link": {
- "r4-link1": {}
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -830,12 +928,18 @@
"neighbor": {
"d1": {
"dest_link": {
- "r4-link1": {}
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
},
"d2": {
"dest_link": {
- "r4-link1": {}
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -852,12 +956,18 @@
"neighbor": {
"d1": {
"dest_link": {
- "r4-link2": {}
+ "r4-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
},
"d2": {
"dest_link": {
- "r4-link2": {}
+ "r4-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -868,12 +978,18 @@
"neighbor": {
"d1": {
"dest_link": {
- "r4-link2": {}
+ "r4-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
},
"d2": {
"dest_link": {
- "r4-link2": {}
+ "r4-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
}
}
}
@@ -885,3 +1001,4 @@
}
}
}
+
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index a236a916b5..2f1f67439f 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -44,6 +44,7 @@ from lib.common_config import (
FRRCFG_FILE,
retry,
get_ipv6_linklocal_address,
+ get_frr_ipv6_linklocal
)
LOGDIR = "/tmp/topotests/"
@@ -265,6 +266,11 @@ def __create_bgp_global(tgen, input_dict, router, build=False):
config_data.append("bgp router-id {}".format(router_id))
config_data.append("no bgp network import-check")
+ bgp_peer_grp_data = bgp_data.setdefault("peer-group", {})
+
+ if "peer-group" in bgp_data and bgp_peer_grp_data:
+ peer_grp_data = __create_bgp_peer_group(tgen, bgp_peer_grp_data, router)
+ config_data.extend(peer_grp_data)
bst_path = bgp_data.setdefault("bestpath", None)
if bst_path:
@@ -380,6 +386,7 @@ def __create_bgp_unicast_neighbor(
addr_data = addr_dict["unicast"]
if addr_data:
config_data.append("address-family {} unicast".format(addr_type))
+
advertise_network = addr_data.setdefault("advertise_networks", [])
for advertise_network_dict in advertise_network:
network = advertise_network_dict["network"]
@@ -404,14 +411,29 @@ def __create_bgp_unicast_neighbor(
config_data.append(cmd)
+ import_cmd = addr_data.setdefault("import", {})
+ if import_cmd:
+ try:
+ if import_cmd["delete"]:
+ config_data.append("no import vrf {}".format(import_cmd["vrf"]))
+ except KeyError:
+ config_data.append("import vrf {}".format(import_cmd["vrf"]))
+
max_paths = addr_data.setdefault("maximum_paths", {})
if max_paths:
ibgp = max_paths.setdefault("ibgp", None)
ebgp = max_paths.setdefault("ebgp", None)
+ del_cmd = max_paths.setdefault("delete", False)
if ibgp:
- config_data.append("maximum-paths ibgp {}".format(ibgp))
+ if del_cmd:
+ config_data.append("no maximum-paths ibgp {}".format(ibgp))
+ else:
+ config_data.append("maximum-paths ibgp {}".format(ibgp))
if ebgp:
- config_data.append("maximum-paths {}".format(ebgp))
+ if del_cmd:
+ config_data.append("no maximum-paths {}".format(ebgp))
+ else:
+ config_data.append("maximum-paths {}".format(ebgp))
aggregate_addresses = addr_data.setdefault("aggregate_address", [])
for aggregate_address in aggregate_addresses:
@@ -649,6 +671,38 @@ def __create_l2vpn_evpn_address_family(
return config_data
+def __create_bgp_peer_group(topo, input_dict, router):
+ """
+ Helper API to create neighbor specific configuration
+
+ Parameters
+ ----------
+ * `topo` : json file data
+ * `input_dict` : Input dict data, required when configuring from testcase
+ * `router` : router id to be configured
+ """
+ config_data = []
+ logger.debug("Entering lib API: __create_bgp_peer_group()")
+
+ for grp, grp_dict in input_dict.items():
+ config_data.append("neighbor {} peer-group".format(grp))
+ neigh_cxt = "neighbor {} ".format(grp)
+ update_source = grp_dict.setdefault("update-source", None)
+ remote_as = grp_dict.setdefault("remote-as", None)
+ capability = grp_dict.setdefault("capability", None)
+ if update_source:
+ config_data.append("{} update-source {}".format(neigh_cxt, update_source))
+
+ if remote_as:
+ config_data.append("{} remote-as {}".format(neigh_cxt, remote_as))
+
+ if capability:
+ config_data.append("{} capability {}".format(neigh_cxt, capability))
+
+ logger.debug("Exiting lib API: __create_bgp_peer_group()")
+ return config_data
+
+
def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
"""
Helper API to create neighbor specific configuration
@@ -660,10 +714,9 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
* `input_dict` : Input dict data, required when configuring from testcase
* `router` : router id to be configured
"""
-
config_data = []
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
+ tgen = get_topogen()
bgp_data = input_dict["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
@@ -672,35 +725,91 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
nh_details = topo[name]
if "vrfs" in topo[router] or type(nh_details["bgp"]) is list:
- remote_as = nh_details["bgp"][0]["local_as"]
+ for vrf_data in nh_details["bgp"]:
+ if "vrf" in nh_details["links"][dest_link] and "vrf" in vrf_data:
+ if nh_details["links"][dest_link]["vrf"] == vrf_data["vrf"]:
+ remote_as = vrf_data["local_as"]
+ break
+ else:
+ if "vrf" not in vrf_data:
+ remote_as = vrf_data["local_as"]
+ break
+
else:
remote_as = nh_details["bgp"]["local_as"]
update_source = None
- if dest_link in nh_details["links"].keys():
- ip_addr = nh_details["links"][dest_link][addr_type].split("/")[0]
- # Loopback interface
- if "source_link" in peer and peer["source_link"] == "lo":
- update_source = topo[router]["links"]["lo"][addr_type].split("/")[0]
+ if "neighbor_type" in peer and peer["neighbor_type"] == "unnumbered":
+ ip_addr = nh_details["links"][dest_link]["peer-interface"]
+ elif "neighbor_type" in peer and peer["neighbor_type"] == "link-local":
+ intf = topo[name]["links"][dest_link]["interface"]
+ ip_addr = get_frr_ipv6_linklocal(tgen, name, intf)
+ elif dest_link in nh_details["links"].keys():
+ try:
+ ip_addr = nh_details["links"][dest_link][addr_type].split("/")[0]
+ except KeyError:
+ intf = topo[name]["links"][dest_link]["interface"]
+ ip_addr = get_frr_ipv6_linklocal(tgen, name, intf)
+ if "delete" in peer and peer["delete"]:
+ neigh_cxt = "no neighbor {}".format(ip_addr)
+ config_data.append("{}".format(neigh_cxt))
+ return config_data
+ else:
+ neigh_cxt = "neighbor {}".format(ip_addr)
- neigh_cxt = "neighbor {}".format(ip_addr)
+ if "peer-group" in peer:
+ config_data.append(
+ "neighbor {} interface peer-group {}".format(
+ ip_addr, peer["peer-group"]
+ )
+ )
+
+ # Loopback interface
+ if "source_link" in peer:
+ if peer["source_link"] == "lo":
+ update_source = topo[router]["links"]["lo"][addr_type].split("/")[0]
+ else:
+ update_source = topo[router]["links"][peer["source_link"]][
+ "interface"
+ ]
+ if "peer-group" not in peer:
+ if "neighbor_type" in peer and peer["neighbor_type"] == "unnumbered":
+ config_data.append(
+ "{} interface remote-as {}".format(neigh_cxt, remote_as)
+ )
+ elif add_neigh:
+ config_data.append("{} remote-as {}".format(neigh_cxt, remote_as))
- if add_neigh:
- config_data.append("{} remote-as {}".format(neigh_cxt, remote_as))
if addr_type == "ipv6":
config_data.append("address-family ipv6 unicast")
config_data.append("{} activate".format(neigh_cxt))
+ if "neighbor_type" in peer and peer["neighbor_type"] == "link-local":
+ config_data.append(
+ "{} update-source {}".format(
+ neigh_cxt, nh_details["links"][dest_link]["peer-interface"]
+ )
+ )
+ config_data.append(
+ "{} interface {}".format(
+ neigh_cxt, nh_details["links"][dest_link]["peer-interface"]
+ )
+ )
+
disable_connected = peer.setdefault("disable_connected_check", False)
keep_alive = peer.setdefault("keepalivetimer", 3)
hold_down = peer.setdefault("holddowntimer", 10)
password = peer.setdefault("password", None)
no_password = peer.setdefault("no_password", None)
+ capability = peer.setdefault("capability", None)
max_hop_limit = peer.setdefault("ebgp_multihop", 1)
+
graceful_restart = peer.setdefault("graceful-restart", None)
graceful_restart_helper = peer.setdefault("graceful-restart-helper", None)
graceful_restart_disable = peer.setdefault("graceful-restart-disable", None)
+ if capability:
+ config_data.append("{} capability {}".format(neigh_cxt, capability))
if update_source:
config_data.append(
@@ -718,7 +827,6 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
config_data.append(
"{} timers {} {}".format(neigh_cxt, keep_alive, hold_down)
)
-
if graceful_restart:
config_data.append("{} graceful-restart".format(neigh_cxt))
elif graceful_restart == False:
@@ -768,7 +876,7 @@ def __create_bgp_unicast_address_family(
config_data = []
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
-
+ tgen = get_topogen()
bgp_data = input_dict["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
@@ -784,16 +892,34 @@ def __create_bgp_unicast_address_family(
for destRouterLink, data in sorted(nh_details["links"].items()):
if "type" in data and data["type"] == "loopback":
if dest_link == destRouterLink:
- ip_addr = nh_details["links"][destRouterLink][
- addr_type
- ].split("/")[0]
+ ip_addr = (
+ nh_details["links"][destRouterLink][addr_type]
+ .split("/")[0]
+ .lower()
+ )
# Physical interface
else:
- if dest_link in nh_details["links"].keys():
-
- ip_addr = nh_details["links"][dest_link][addr_type].split("/")[0]
- if addr_type == "ipv4" and bgp_data["ipv6"]:
+ # check the neighbor type if un numbered nbr, use interface.
+ if "neighbor_type" in peer and peer["neighbor_type"] == "unnumbered":
+ ip_addr = nh_details["links"][dest_link]["peer-interface"]
+ elif "neighbor_type" in peer and peer["neighbor_type"] == "link-local":
+ intf = topo[peer_name]["links"][dest_link]["interface"]
+ ip_addr = get_frr_ipv6_linklocal(tgen, peer_name, intf)
+ elif dest_link in nh_details["links"].keys():
+ try:
+ ip_addr = nh_details["links"][dest_link][addr_type].split("/")[
+ 0
+ ]
+ except KeyError:
+ intf = topo[peer_name]["links"][dest_link]["interface"]
+ ip_addr = get_frr_ipv6_linklocal(tgen, peer_name, intf)
+ if (
+ addr_type == "ipv4"
+ and bgp_data["ipv6"]
+ and check_address_types("ipv6")
+ and "ipv6" in nh_details["links"][dest_link]
+ ):
deactivate = nh_details["links"][dest_link]["ipv6"].split("/")[
0
]
@@ -822,6 +948,7 @@ def __create_bgp_unicast_address_family(
prefix_lists = peer.setdefault("prefix_lists", {})
route_maps = peer.setdefault("route_maps", {})
no_send_community = peer.setdefault("no_send_community", None)
+ capability = peer.setdefault("capability", None)
allowas_in = peer.setdefault("allowas-in", None)
# next-hop-self
@@ -841,6 +968,11 @@ def __create_bgp_unicast_address_family(
"no {} send-community {}".format(neigh_cxt, no_send_community)
)
+ # capability_ext_nh
+ if capability and addr_type == "ipv6":
+ config_data.append("address-family ipv4 unicast")
+ config_data.append("{} activate".format(neigh_cxt))
+
if "allowas_in" in peer:
allow_as_in = peer["allowas_in"]
config_data.append("{} allowas-in {}".format(neigh_cxt, allow_as_in))
@@ -1067,33 +1199,37 @@ def verify_bgp_convergence(tgen, topo, dut=None, expected=True):
API will verify if BGP is converged with in the given time frame.
Running "show bgp summary json" command and verify bgp neighbor
state is established,
+
Parameters
----------
* `tgen`: topogen object
* `topo`: input json file data
* `dut`: device under test
- * `expected` : expected results from API, by-default True
Usage
-----
# To veriry is BGP is converged for all the routers used in
topology
results = verify_bgp_convergence(tgen, topo, dut="r1")
+
Returns
-------
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_bgp_convergence()")
+ result = False
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ tgen = get_topogen()
for router, rnode in tgen.routers().items():
- if dut is not None and dut != router:
+ if 'bgp' not in topo['routers'][router]:
continue
- if "bgp" not in topo["routers"][router]:
+ if dut is not None and dut != router:
continue
logger.info("Verifying BGP Convergence on router %s:", router)
- show_bgp_json = run_frr_cmd(rnode, "show bgp vrf all summary json", isjson=True)
+ show_bgp_json = run_frr_cmd(rnode, "show bgp vrf all summary json",
+ isjson=True)
# Verifying output dictionary show_bgp_json is empty or not
if not bool(show_bgp_json):
errormsg = "BGP is not running"
@@ -1115,100 +1251,6 @@ def verify_bgp_convergence(tgen, topo, dut=None, expected=True):
# To find neighbor ip type
bgp_addr_type = bgp_data["address_family"]
- if "ipv4" in bgp_addr_type or "ipv6" in bgp_addr_type:
- for addr_type in bgp_addr_type.keys():
- if not check_address_types(addr_type):
- continue
- total_peer = 0
-
- bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
-
- for bgp_neighbor in bgp_neighbors:
- total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"])
-
- for addr_type in bgp_addr_type.keys():
- if not check_address_types(addr_type):
- continue
- bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
-
- no_of_peer = 0
- for bgp_neighbor, peer_data in bgp_neighbors.items():
- for dest_link in peer_data["dest_link"].keys():
- data = topo["routers"][bgp_neighbor]["links"]
- if dest_link in data:
- peer_details = peer_data["dest_link"][dest_link]
- # for link local neighbors
- if (
- "neighbor_type" in peer_details
- and peer_details["neighbor_type"] == "link-local"
- ):
- neighbor_ip = get_ipv6_linklocal_address(
- topo["routers"], bgp_neighbor, dest_link
- )
- elif "source_link" in peer_details:
- neighbor_ip = topo["routers"][bgp_neighbor][
- "links"
- ][peer_details["source_link"]][addr_type].split(
- "/"
- )[
- 0
- ]
- elif (
- "neighbor_type" in peer_details
- and peer_details["neighbor_type"] == "unnumbered"
- ):
- neighbor_ip = data[dest_link]["peer-interface"]
- else:
- neighbor_ip = data[dest_link][addr_type].split("/")[
- 0
- ]
- nh_state = None
-
- if addr_type == "ipv4":
- if "ipv4Unicast" in show_bgp_json[vrf]:
- ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
- "peers"
- ]
- nh_state = ipv4_data[neighbor_ip]["state"]
- else:
- if "ipv6Unicast" in show_bgp_json[vrf]:
- ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
- "peers"
- ]
- nh_state = ipv6_data[neighbor_ip]["state"]
- if nh_state == "Established":
- no_of_peer += 1
-
- if "l2vpn" in bgp_addr_type:
- if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
- if no_of_peer == total_peer:
- logger.info(
- "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
- router,
- vrf,
- addr_type,
- )
- else:
- errormsg = (
- "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
- % (router, vrf, addr_type)
- )
- return errormsg
- else:
- if no_of_peer == total_peer:
- logger.info(
- "[DUT: %s] VRF: %s, BGP is Converged for %s address-family",
- router,
- vrf,
- addr_type,
- )
- else:
- errormsg = (
- "[DUT: %s] VRF: %s, BGP is not converged for %s address-family"
- % (router, vrf, addr_type)
- )
- return errormsg
-
if "l2vpn" in bgp_addr_type:
total_evpn_peer = 0
@@ -1224,46 +1266,120 @@ def verify_bgp_convergence(tgen, topo, dut=None, expected=True):
data = topo["routers"][bgp_neighbor]["links"]
for dest_link in dest_link_dict.keys():
if dest_link in data:
- peer_details = peer_data[_addr_type][dest_link]
+ peer_details = \
+ peer_data[_addr_type][dest_link]
- neighbor_ip = data[dest_link][_addr_type].split("/")[0]
+ neighbor_ip = \
+ data[dest_link][_addr_type].split(
+ "/")[0]
nh_state = None
- if (
- "ipv4Unicast" in show_bgp_json[vrf]
- or "ipv6Unicast" in show_bgp_json[vrf]
- ):
- errormsg = (
- "[DUT: %s] VRF: %s, "
- "ipv4Unicast/ipv6Unicast"
- " address-family present"
- " under l2vpn" % (router, vrf)
- )
+ if "ipv4Unicast" in show_bgp_json[vrf] or \
+ "ipv6Unicast" in show_bgp_json[vrf]:
+ errormsg = ("[DUT: %s] VRF: %s, "
+ "ipv4Unicast/ipv6Unicast"
+ " address-family present"
+ " under l2vpn" % (router,
+ vrf))
return errormsg
- l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
- "peers"
- ]
- nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
+ l2VpnEvpn_data = \
+ show_bgp_json[vrf]["l2VpnEvpn"][
+ "peers"]
+ nh_state = \
+ l2VpnEvpn_data[neighbor_ip]["state"]
if nh_state == "Established":
no_of_evpn_peer += 1
if no_of_evpn_peer == total_evpn_peer:
- logger.info(
- "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
- router,
- vrf,
- )
+ logger.info("[DUT: %s] VRF: %s, BGP is Converged for "
+ "epvn peers", router, vrf)
+ result = True
else:
- errormsg = (
- "[DUT: %s] VRF: %s, BGP is not converged "
- "for evpn peers" % (router, vrf)
- )
+ errormsg = ("[DUT: %s] VRF: %s, BGP is not converged "
+ "for evpn peers" % (router, vrf))
return errormsg
+ else:
+ total_peer = 0
+ for addr_type in bgp_addr_type.keys():
+ if not check_address_types(addr_type):
+ continue
- logger.debug("Exiting API: verify_bgp_convergence()")
- return True
+ bgp_neighbors = \
+ bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ for bgp_neighbor in bgp_neighbors:
+ total_peer += \
+ len(bgp_neighbors[bgp_neighbor]["dest_link"])
+
+ no_of_peer = 0
+ for addr_type in bgp_addr_type.keys():
+ if not check_address_types(addr_type):
+ continue
+ bgp_neighbors = \
+ bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for dest_link in peer_data["dest_link"].\
+ keys():
+ data = \
+ topo["routers"][bgp_neighbor]["links"]
+ if dest_link in data:
+ peer_details = \
+ peer_data['dest_link'][dest_link]
+ # for link local neighbors
+ if "neighbor_type" in peer_details and \
+ peer_details["neighbor_type"] == \
+ 'link-local':
+ intf = topo["routers"][bgp_neighbor][
+ "links"][dest_link]["interface"]
+ neighbor_ip = get_frr_ipv6_linklocal(
+ tgen, bgp_neighbor, intf)
+ elif "source_link" in peer_details:
+ neighbor_ip = \
+ topo["routers"][bgp_neighbor][
+ "links"][peer_details[
+ 'source_link']][
+ addr_type].\
+ split("/")[0]
+ elif "neighbor_type" in peer_details and \
+ peer_details["neighbor_type"] == \
+ 'unnumbered':
+ neighbor_ip = \
+ data[dest_link]["peer-interface"]
+ else:
+ neighbor_ip = \
+ data[dest_link][addr_type].split(
+ "/")[0]
+ nh_state = None
+ neighbor_ip = neighbor_ip.lower()
+ if addr_type == "ipv4":
+ ipv4_data = show_bgp_json[vrf][
+ "ipv4Unicast"]["peers"]
+ nh_state = \
+ ipv4_data[neighbor_ip]["state"]
+ else:
+ ipv6_data = show_bgp_json[vrf][
+ "ipv6Unicast"]["peers"]
+ if neighbor_ip in ipv6_data:
+ nh_state = \
+ ipv6_data[neighbor_ip]["state"]
+
+ if nh_state == "Established":
+ no_of_peer += 1
+
+ if no_of_peer == total_peer and no_of_peer > 0:
+ logger.info("[DUT: %s] VRF: %s, BGP is Converged",
+ router, vrf)
+ result = True
+ else:
+ errormsg = ("[DUT: %s] VRF: %s, BGP is not converged"
+ % (router, vrf))
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return result
@retry(retry_timeout=16)
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 9e38608631..6a02e50127 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -365,7 +365,7 @@ def create_common_configuration(
return True
-def kill_router_daemons(tgen, router, daemons):
+def kill_router_daemons(tgen, router, daemons, save_config=True):
"""
Router's current config would be saved to /etc/frr/ for each daemon
and daemon would be killed forcefully using SIGKILL.
@@ -379,9 +379,10 @@ def kill_router_daemons(tgen, router, daemons):
try:
router_list = tgen.routers()
- # Saving router config to /etc/frr, which will be loaded to router
- # when it starts
- router_list[router].vtysh_cmd("write memory")
+ if save_config:
+ # Saving router config to /etc/frr, which will be loaded to router
+ # when it starts
+ router_list[router].vtysh_cmd("write memory")
# Kill Daemons
result = router_list[router].killDaemons(daemons)
@@ -496,7 +497,7 @@ def reset_config_on_routers(tgen, routerName=None):
f.close()
run_cfg_file = "{}/{}/frr.sav".format(TMPDIR, rname)
init_cfg_file = "{}/{}/frr_json_initial.conf".format(TMPDIR, rname)
- command = "/usr/lib/frr/frr-reload.py --input {} --test {} > {}".format(
+ command = "/usr/lib/frr/frr-reload.py --test --test-reset --input {} {} > {}".format(
run_cfg_file, init_cfg_file, dname
)
result = call(command, shell=True, stderr=SUB_STDOUT, stdout=SUB_PIPE)
@@ -526,37 +527,9 @@ def reset_config_on_routers(tgen, routerName=None):
raise InvalidCLIError(out_data)
raise InvalidCLIError("Unknown error in %s", output)
- f = open(dname, "r")
delta = StringIO()
- delta.write("configure terminal\n")
- t_delta = f.read()
-
- # Don't disable debugs
- check_debug = True
-
- for line in t_delta.split("\n"):
- line = line.strip()
- if line == "Lines To Delete" or line == "===============" or not line:
- continue
-
- if line == "Lines To Add":
- check_debug = False
- continue
-
- if line == "============" or not line:
- continue
-
- # Leave debugs and log output alone
- if check_debug:
- if "debug" in line or "log file" in line:
- continue
-
- delta.write(line)
- delta.write("\n")
-
- f.close()
-
- delta.write("end\n")
+ with open(dname, "r") as f:
+ delta.write(f.read())
output = router.vtysh_multicmd(delta.getvalue(), pretty_output=False)
@@ -636,6 +609,7 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
return True
+
def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None):
"""
API to get the link local ipv6 address of a particular interface using
@@ -668,38 +642,48 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None):
else:
cmd = "show interface"
- ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd))
-
- # Fix newlines (make them all the same)
- ifaces = ("\n".join(ifaces.splitlines()) + "\n").splitlines()
-
- interface = None
- ll_per_if_count = 0
- for line in ifaces:
- # Interface name
- m = re_search("Interface ([a-zA-Z0-9-]+) is", line)
- if m:
- interface = m.group(1).split(" ")[0]
- ll_per_if_count = 0
-
- # Interface ip
- m1 = re_search("inet6 (fe80[:a-fA-F0-9]+[/0-9]+)", line)
- if m1:
- local = m1.group(1)
- ll_per_if_count += 1
- if ll_per_if_count > 1:
- linklocal += [["%s-%s" % (interface, ll_per_if_count), local]]
- else:
- linklocal += [[interface, local]]
-
- if linklocal:
- if intf:
- return [_linklocal[1] for _linklocal in linklocal if _linklocal[0] == intf][
- 0
- ].split("/")[0]
- return linklocal
- else:
- errormsg = "Link local ip missing on router {}"
+ linklocal = []
+ if vrf:
+ cmd = "show interface vrf {}".format(vrf)
+ else:
+ cmd = "show interface"
+ for chk_ll in range(0, 60):
+ sleep(1/4)
+ ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd))
+ # Fix newlines (make them all the same)
+ ifaces = ('\n'.join(ifaces.splitlines()) + '\n').splitlines()
+
+ interface = None
+ ll_per_if_count = 0
+ for line in ifaces:
+ # Interface name
+ m = re_search('Interface ([a-zA-Z0-9-]+) is', line)
+ if m:
+ interface = m.group(1).split(" ")[0]
+ ll_per_if_count = 0
+
+ # Interface ip
+ m1 = re_search('inet6 (fe80[:a-fA-F0-9]+[\/0-9]+)',
+ line)
+ if m1:
+ local = m1.group(1)
+ ll_per_if_count += 1
+ if ll_per_if_count > 1:
+ linklocal += [["%s-%s" %
+ (interface, ll_per_if_count), local]]
+ else:
+ linklocal += [[interface, local]]
+
+ try:
+ if linklocal:
+ if intf:
+ return [_linklocal[1] for _linklocal in linklocal if _linklocal[0]==intf][0].\
+ split("/")[0]
+ return linklocal
+ except IndexError:
+ continue
+
+ errormsg = "Link local ip missing on router {}".format(router)
return errormsg
@@ -712,20 +696,36 @@ def generate_support_bundle():
tgen = get_topogen()
router_list = tgen.routers()
- test_name = sys._getframe(2).f_code.co_name
+ test_name = os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0]
+
TMPDIR = os.path.join(LOGDIR, tgen.modname)
+ bundle_procs = {}
for rname, rnode in router_list.items():
- logger.info("Generating support bundle for {}".format(rname))
+ logger.info("Spawn collection of support bundle for %s", rname)
rnode.run("mkdir -p /var/log/frr")
+ bundle_procs[rname] = tgen.net[rname].popen(
+ "/usr/lib/frr/generate_support_bundle.py",
+ stdin=None,
+ stdout=SUB_PIPE,
+ stderr=SUB_PIPE,
+ )
- # Support only python3 going forward
- bundle_log = rnode.run("env python3 /usr/lib/frr/generate_support_bundle.py")
-
- logger.info(bundle_log)
-
+ for rname, rnode in router_list.items():
dst_bundle = "{}/{}/support_bundles/{}".format(TMPDIR, rname, test_name)
src_bundle = "/var/log/frr"
+
+ output, error = bundle_procs[rname].communicate()
+
+ logger.info("Saving support bundle for %s", rname)
+ if output:
+ logger.info(
+ "Output from collecting support bundle for %s:\n%s", rname, output
+ )
+ if error:
+ logger.warning(
+ "Error from collecting support bundle for %s:\n%s", rname, error
+ )
rnode.run("rm -rf {}".format(dst_bundle))
rnode.run("mkdir -p {}".format(dst_bundle))
rnode.run("mv -f {}/* {}".format(src_bundle, dst_bundle))
@@ -1829,6 +1829,14 @@ def create_interfaces_cfg(tgen, topo, build=False):
else:
interface_data.append("ipv6 address {}".format(intf_addr))
+ # Wait for vrf interfaces to get link local address once they are up
+ if not destRouterLink == 'lo' and 'vrf' in topo[c_router][
+ 'links'][destRouterLink]:
+ vrf = topo[c_router]['links'][destRouterLink]['vrf']
+ intf = topo[c_router]['links'][destRouterLink]['interface']
+ ll = get_frr_ipv6_linklocal(tgen, c_router, intf=intf,
+ vrf = vrf)
+
if "ipv6-link-local" in data:
intf_addr = c_data["links"][destRouterLink]["ipv6-link-local"]
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index ade5933504..b998878118 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -801,8 +801,8 @@ class TopoRouter(TopoGear):
try:
return json.loads(output)
- except ValueError:
- logger.warning("vtysh_cmd: failed to convert json output")
+ except ValueError as error:
+ logger.warning("vtysh_cmd: %s: failed to convert json output: %s: %s", self.name, str(output), str(error))
return {}
def vtysh_multicmd(self, commands, pretty_output=True, daemon=None):
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 4c0c6ab54a..b516a67d5c 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -1152,6 +1152,18 @@ class Router(Node):
self.reportCores = True
self.version = None
+ self.ns_cmd = "sudo nsenter -m -n -t {} ".format(self.pid)
+ try:
+ # Allow escaping from running inside docker
+ cgroup = open("/proc/1/cgroup").read()
+ m = re.search("[0-9]+:cpuset:/docker/([a-f0-9]+)", cgroup)
+ if m:
+ self.ns_cmd = "docker exec -it {} ".format(m.group(1)) + self.ns_cmd
+ except IOError:
+ pass
+ else:
+ logger.debug("CMD to enter {}: {}".format(self.name, self.ns_cmd))
+
def _config_frr(self, **params):
"Configure FRR binaries"
self.daemondir = params.get("frrdir")
@@ -1353,7 +1365,7 @@ class Router(Node):
term = topo_terminal if topo_terminal else "xterm"
makeTerm(self, title=title if title else cmd, term=term, cmd=cmd)
else:
- nscmd = "sudo nsenter -m -n -t {} {}".format(self.pid, cmd)
+ nscmd = self.ns_cmd + cmd
if "TMUX" in os.environ:
self.cmd("tmux select-layout main-horizontal")
wcmd = "tmux split-window -h"
@@ -1454,11 +1466,13 @@ class Router(Node):
def startRouterDaemons(self, daemons=None):
"Starts all FRR daemons for this router."
+ asan_abort = g_extra_config["asan_abort"]
gdb_breakpoints = g_extra_config["gdb_breakpoints"]
gdb_daemons = g_extra_config["gdb_daemons"]
gdb_routers = g_extra_config["gdb_routers"]
valgrind_extra = g_extra_config["valgrind_extra"]
valgrind_memleaks = g_extra_config["valgrind_memleaks"]
+ strace_daemons = g_extra_config["strace_daemons"]
bundle_data = ""
@@ -1485,7 +1499,6 @@ class Router(Node):
os.path.join(self.daemondir, "bgpd") + " -v"
).split()[2]
logger.info("{}: running version: {}".format(self.name, self.version))
-
# If `daemons` was specified then some upper API called us with
# specific daemons, otherwise just use our own configuration.
daemons_list = []
@@ -1509,13 +1522,20 @@ class Router(Node):
else:
binary = os.path.join(self.daemondir, daemon)
- cmdenv = "ASAN_OPTIONS=log_path={0}.asan".format(daemon)
+ cmdenv = "ASAN_OPTIONS="
+ if asan_abort:
+ cmdenv = "abort_on_error=1:"
+ cmdenv += "log_path={0}/{1}.{2}.asan ".format(self.logdir, self.name, daemon)
+
if valgrind_memleaks:
this_dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
supp_file = os.path.abspath(os.path.join(this_dir, "../../../tools/valgrind.supp"))
cmdenv += " /usr/bin/valgrind --num-callers=50 --log-file={1}/{2}.valgrind.{0}.%p --leak-check=full --suppressions={3}".format(daemon, self.logdir, self.name, supp_file)
if valgrind_extra:
cmdenv += "--gen-suppressions=all --expensive-definedness-checks=yes"
+ elif daemon in strace_daemons or "all" in strace_daemons:
+ cmdenv = "strace -f -D -o {1}/{2}.strace.{0} ".format(daemon, self.logdir, self.name)
+
cmdopt = "{} --log file:{}.log --log-level debug".format(
daemon_opts, daemon
)
diff --git a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
index e55e30270d..b880e0e462 100755
--- a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
+++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
@@ -526,9 +526,14 @@ def test_multicast_data_traffic_static_RP_send_traffic_then_join_p0(request):
{"dut": "r2", "src_address": source, "iif": "r2-f1-eth0", "oil": "r2-l1-eth2"},
{"dut": "f1", "src_address": source, "iif": "f1-i2-eth1", "oil": "f1-r2-eth3"},
]
+ # On timeout change from default of 80 to 120: failures logs indicate times 90+
+ # seconds for success on the 2nd entry in the above table. Using 100s here restores
+ # previous 80 retries with 2s wait if we assume .5s per vtysh/show ip mroute runtime
+ # (41 * (2 + .5)) == 102.
for data in input_dict:
result = verify_ip_mroutes(
- tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"],
+ retry_timeout=102
)
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
diff --git a/tests/topotests/ospf_gr_topo1/__init__.py b/tests/topotests/ospf_gr_topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/__init__.py
diff --git a/tests/topotests/ospf_gr_topo1/rt1/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt1/ospfd.conf
new file mode 100644
index 0000000000..9c04b74d35
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt1/ospfd.conf
@@ -0,0 +1,32 @@
+password 1
+hostname rt1
+log file ospfd.log
+log commands
+!
+debug ospf zebra
+debug ospf event
+debug ospf lsa
+debug ospf te
+debug ospf packet all
+debug ospf packet ls-update detail
+debug ospf ism
+debug ospf nsm
+debug ospf nssa
+debug ospf graceful-restart
+!
+interface lo
+ ip ospf area 1
+!
+interface eth-rt2
+ ip ospf network point-to-point
+ ip ospf area 1
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+router ospf
+ router-id 1.1.1.1
+ capability opaque
+ redistribute connected
+ graceful-restart grace-period 120
+ graceful-restart helper-only
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_database.json b/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_database.json
new file mode 100644
index 0000000000..d01ac74c17
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_database.json
@@ -0,0 +1,98 @@
+{
+ "routerId":"1.1.1.1",
+ "areas":{
+ "0.0.0.1":{
+ "routerLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"1.1.1.1",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"2.2.2.2",
+ "numOfRouterLinks":2
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"2.2.2.2\/32"
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"3.3.3.3\/32"
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"4.4.4.4\/32"
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"5.5.5.5\/32"
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"6.6.6.6\/32"
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"7.7.7.7\/32"
+ },
+ {
+ "lsId":"10.0.2.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.2.0\/24"
+ },
+ {
+ "lsId":"10.0.3.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.3.0\/24"
+ },
+ {
+ "lsId":"10.0.4.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.4.0\/24"
+ },
+ {
+ "lsId":"10.0.5.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.5.0\/24"
+ },
+ {
+ "lsId":"10.0.6.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.6.0\/24"
+ }
+ ],
+ "asbrSummaryLinkStates":[
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"2.2.2.2"
+ }
+ ]
+ }
+ },
+ "asExternalLinkStates":[
+ {
+ "lsId":"172.16.1.0",
+ "advertisedRouter":"1.1.1.1",
+ "metricType":"E2",
+ "route":"172.16.1.0\/24",
+ "tag":0
+ },
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"6.6.6.6",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..ed290323a4
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_neighbor.json
@@ -0,0 +1,11 @@
+{
+ "neighbors":{
+ "2.2.2.2":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.1.2",
+ "ifaceName":"eth-rt2:10.0.1.1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_route.json b/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_route.json
new file mode 100644
index 0000000000..548ca1e2d1
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_route.json
@@ -0,0 +1,180 @@
+{
+ "1.1.1.1\/32":{
+ "routeType":"N",
+ "cost":0,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"lo"
+ }
+ ]
+ },
+ "2.2.2.2\/32":{
+ "routeType":"N IA",
+ "cost":10,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "3.3.3.3\/32":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "4.4.4.4\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "5.5.5.5\/32":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "6.6.6.6\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "7.7.7.7\/32":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "10.0.1.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt2"
+ }
+ ]
+ },
+ "10.0.2.0\/24":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "10.0.3.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "10.0.4.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "10.0.5.0\/24":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "10.0.6.0\/24":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "2.2.2.2":{
+ "routeType":"R ",
+ "cost":10,
+ "area":"0.0.0.1",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "6.6.6.6":{
+ "routeType":"R ",
+ "cost":30,
+ "area":"0.0.0.1",
+ "IA":true,
+ "routerType":"asbr",
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "192.168.1.0\/24":{
+ "routeType":"N E2",
+ "cost":40,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "via":"eth-rt2"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt1/show_ip_route.json b/tests/topotests/ospf_gr_topo1/rt1/show_ip_route.json
new file mode 100644
index 0000000000..3dce1eee3e
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt1/show_ip_route.json
@@ -0,0 +1,210 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"lo"
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "7.7.7.7\/32":[
+ {
+ "prefix":"7.7.7.7\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "192.168.1.0\/24":[
+ {
+ "prefix":"192.168.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt1/zebra.conf b/tests/topotests/ospf_gr_topo1/rt1/zebra.conf
new file mode 100644
index 0000000000..183cd3df48
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt1/zebra.conf
@@ -0,0 +1,23 @@
+password 1
+hostname rt1
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 1.1.1.1/32
+!
+interface stub1
+ ip address 172.16.1.1/24
+!
+interface eth-rt2
+ ip address 10.0.1.1/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt2/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt2/ospfd.conf
new file mode 100644
index 0000000000..922db8c8cc
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt2/ospfd.conf
@@ -0,0 +1,37 @@
+password 1
+hostname rt2
+log file ospfd.log
+log commands
+!
+debug ospf zebra
+debug ospf event
+debug ospf lsa
+debug ospf te
+debug ospf packet all
+debug ospf packet ls-update detail
+debug ospf ism
+debug ospf nsm
+debug ospf nssa
+debug ospf graceful-restart
+!
+interface lo
+ ip ospf area 0
+!
+interface eth-rt1
+ ip ospf network point-to-point
+ ip ospf area 1
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+interface eth-rt3
+ ip ospf network point-to-point
+ ip ospf area 0
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+router ospf
+ router-id 2.2.2.2
+ capability opaque
+ graceful-restart grace-period 120
+ graceful-restart helper-only
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_database.json b/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_database.json
new file mode 100644
index 0000000000..40c3e82d6a
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_database.json
@@ -0,0 +1,160 @@
+{
+ "routerId":"2.2.2.2",
+ "areas":{
+ "0.0.0.0":{
+ "routerLinkStates":[
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"2.2.2.2",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"3.3.3.3",
+ "numOfRouterLinks":7
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"4.4.4.4",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"6.6.6.6",
+ "numOfRouterLinks":3
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"1.1.1.1\/32"
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"5.5.5.5\/32"
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"7.7.7.7\/32"
+ },
+ {
+ "lsId":"10.0.1.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.1.0\/24"
+ },
+ {
+ "lsId":"10.0.5.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.5.0\/24"
+ },
+ {
+ "lsId":"10.0.6.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.6.0\/24"
+ }
+ ],
+ "asbrSummaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"2.2.2.2"
+ }
+ ]
+ },
+ "0.0.0.1":{
+ "routerLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"1.1.1.1",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"2.2.2.2",
+ "numOfRouterLinks":2
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"2.2.2.2\/32"
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"3.3.3.3\/32"
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"4.4.4.4\/32"
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"5.5.5.5\/32"
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"6.6.6.6\/32"
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"7.7.7.7\/32"
+ },
+ {
+ "lsId":"10.0.2.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.2.0\/24"
+ },
+ {
+ "lsId":"10.0.3.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.3.0\/24"
+ },
+ {
+ "lsId":"10.0.4.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.4.0\/24"
+ },
+ {
+ "lsId":"10.0.5.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.5.0\/24"
+ },
+ {
+ "lsId":"10.0.6.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.6.0\/24"
+ }
+ ],
+ "asbrSummaryLinkStates":[
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"2.2.2.2"
+ }
+ ]
+ }
+ },
+ "asExternalLinkStates":[
+ {
+ "lsId":"172.16.1.0",
+ "advertisedRouter":"1.1.1.1",
+ "metricType":"E2",
+ "route":"172.16.1.0\/24",
+ "tag":0
+ },
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"6.6.6.6",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..4fe92b0b98
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_neighbor.json
@@ -0,0 +1,18 @@
+{
+ "neighbors":{
+ "1.1.1.1":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.1.1",
+ "ifaceName":"eth-rt1:10.0.1.2"
+ }
+ ],
+ "3.3.3.3":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.2.3",
+ "ifaceName":"eth-rt3:10.0.2.2"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_route.json b/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_route.json
new file mode 100644
index 0000000000..4accb2ba4a
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_route.json
@@ -0,0 +1,201 @@
+{
+ "1.1.1.1\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "via":"eth-rt1"
+ }
+ ]
+ },
+ "2.2.2.2\/32":{
+ "routeType":"N",
+ "cost":0,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"lo"
+ }
+ ]
+ },
+ "3.3.3.3\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "4.4.4.4\/32":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "5.5.5.5\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "6.6.6.6\/32":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "7.7.7.7\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.1.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.1",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt1"
+ }
+ ]
+ },
+ "10.0.2.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.3.0\/24":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.4.0\/24":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.5.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.6.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "1.1.1.1":{
+ "routeType":"R ",
+ "cost":10,
+ "area":"0.0.0.1",
+ "routerType":"asbr",
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "via":"eth-rt1"
+ }
+ ]
+ },
+ "4.4.4.4":{
+ "routeType":"R ",
+ "cost":20,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "6.6.6.6":{
+ "routeType":"R ",
+ "cost":20,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "172.16.1.0\/24":{
+ "routeType":"N E2",
+ "cost":10,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "via":"eth-rt1"
+ }
+ ]
+ },
+ "192.168.1.0\/24":{
+ "routeType":"N E2",
+ "cost":30,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "via":"eth-rt3"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt2/show_ip_route.json b/tests/topotests/ospf_gr_topo1/rt2/show_ip_route.json
new file mode 100644
index 0000000000..8989a45765
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt2/show_ip_route.json
@@ -0,0 +1,224 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt1"
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"lo"
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "7.7.7.7\/32":[
+ {
+ "prefix":"7.7.7.7\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "172.16.1.0\/24":[
+ {
+ "prefix":"172.16.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt1"
+ }
+ ]
+ }
+ ],
+ "192.168.1.0\/24":[
+ {
+ "prefix":"192.168.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt2/zebra.conf b/tests/topotests/ospf_gr_topo1/rt2/zebra.conf
new file mode 100644
index 0000000000..8bde98ad44
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt2/zebra.conf
@@ -0,0 +1,23 @@
+password 1
+hostname rt2
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 2.2.2.2/32
+!
+interface eth-rt1
+ ip address 10.0.1.2/24
+!
+interface eth-rt3
+ ip address 10.0.2.2/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt3/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt3/ospfd.conf
new file mode 100644
index 0000000000..51e48f13da
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt3/ospfd.conf
@@ -0,0 +1,43 @@
+password 1
+hostname rt3
+log file ospfd.log
+log commands
+!
+debug ospf zebra
+debug ospf event
+debug ospf lsa
+debug ospf te
+debug ospf packet all
+debug ospf packet ls-update detail
+debug ospf ism
+debug ospf nsm
+debug ospf nssa
+debug ospf graceful-restart
+!
+interface lo
+ ip ospf area 0
+!
+interface eth-rt2
+ ip ospf network point-to-point
+ ip ospf area 0
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+interface eth-rt4
+ ip ospf network point-to-point
+ ip ospf area 0
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+interface eth-rt6
+ ip ospf network point-to-point
+ ip ospf area 0
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+router ospf
+ router-id 3.3.3.3
+ capability opaque
+ graceful-restart grace-period 120
+ graceful-restart helper-only
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_database.json b/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_database.json
new file mode 100644
index 0000000000..1fc5b546e4
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_database.json
@@ -0,0 +1,83 @@
+{
+ "routerId":"3.3.3.3",
+ "areas":{
+ "0.0.0.0":{
+ "routerLinkStates":[
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"2.2.2.2",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"3.3.3.3",
+ "numOfRouterLinks":7
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"4.4.4.4",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"6.6.6.6",
+ "numOfRouterLinks":3
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"1.1.1.1\/32"
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"5.5.5.5\/32"
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"7.7.7.7\/32"
+ },
+ {
+ "lsId":"10.0.1.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.1.0\/24"
+ },
+ {
+ "lsId":"10.0.5.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.5.0\/24"
+ },
+ {
+ "lsId":"10.0.6.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.6.0\/24"
+ }
+ ],
+ "asbrSummaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"2.2.2.2"
+ }
+ ]
+ }
+ },
+ "asExternalLinkStates":[
+ {
+ "lsId":"172.16.1.0",
+ "advertisedRouter":"1.1.1.1",
+ "metricType":"E2",
+ "route":"172.16.1.0\/24",
+ "tag":0
+ },
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"6.6.6.6",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..e3c36ab9a3
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_neighbor.json
@@ -0,0 +1,25 @@
+{
+ "neighbors":{
+ "2.2.2.2":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.2.2",
+ "ifaceName":"eth-rt2:10.0.2.3"
+ }
+ ],
+ "4.4.4.4":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.3.4",
+ "ifaceName":"eth-rt4:10.0.3.3"
+ }
+ ],
+ "6.6.6.6":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.4.6",
+ "ifaceName":"eth-rt6:10.0.4.3"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_route.json b/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_route.json
new file mode 100644
index 0000000000..b2f37e25a1
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_route.json
@@ -0,0 +1,214 @@
+{
+ "1.1.1.1\/32":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "2.2.2.2\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "3.3.3.3\/32":{
+ "routeType":"N",
+ "cost":0,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"lo"
+ }
+ ]
+ },
+ "4.4.4.4\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "5.5.5.5\/32":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "6.6.6.6\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "7.7.7.7\/32":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "10.0.1.0\/24":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "10.0.2.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt2"
+ }
+ ]
+ },
+ "10.0.3.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt4"
+ }
+ ]
+ },
+ "10.0.4.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt6"
+ }
+ ]
+ },
+ "10.0.5.0\/24":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "10.0.6.0\/24":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "1.1.1.1":{
+ "routeType":"R ",
+ "cost":20,
+ "area":"0.0.0.0",
+ "IA":true,
+ "routerType":"asbr",
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "2.2.2.2":{
+ "routeType":"R ",
+ "cost":10,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "4.4.4.4":{
+ "routeType":"R ",
+ "cost":10,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.3.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "6.6.6.6":{
+ "routeType":"R ",
+ "cost":10,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "172.16.1.0\/24":{
+ "routeType":"N E2",
+ "cost":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "via":"eth-rt2"
+ }
+ ]
+ },
+ "192.168.1.0\/24":{
+ "routeType":"N E2",
+ "cost":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "via":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt3/show_ip_route.json b/tests/topotests/ospf_gr_topo1/rt3/show_ip_route.json
new file mode 100644
index 0000000000..c9a1e18b92
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt3/show_ip_route.json
@@ -0,0 +1,223 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"lo"
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "7.7.7.7\/32":[
+ {
+ "prefix":"7.7.7.7\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "172.16.1.0\/24":[
+ {
+ "prefix":"172.16.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2"
+ }
+ ]
+ }
+ ],
+ "192.168.1.0\/24":[
+ {
+ "prefix":"192.168.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt3/zebra.conf b/tests/topotests/ospf_gr_topo1/rt3/zebra.conf
new file mode 100644
index 0000000000..dfd89cbe5b
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt3/zebra.conf
@@ -0,0 +1,26 @@
+password 1
+hostname rt3
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 3.3.3.3/32
+!
+interface eth-rt2
+ ip address 10.0.2.3/24
+!
+interface eth-rt4
+ ip address 10.0.3.3/24
+!
+interface eth-rt6
+ ip address 10.0.4.3/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt4/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt4/ospfd.conf
new file mode 100644
index 0000000000..a54f27a1d7
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt4/ospfd.conf
@@ -0,0 +1,37 @@
+password 1
+hostname rt4
+log file ospfd.log
+log commands
+!
+debug ospf zebra
+debug ospf event
+debug ospf lsa
+debug ospf te
+debug ospf packet all
+debug ospf packet ls-update detail
+debug ospf ism
+debug ospf nsm
+debug ospf nssa
+debug ospf graceful-restart
+!
+interface lo
+ ip ospf area 0
+!
+interface eth-rt3
+ ip ospf network point-to-point
+ ip ospf area 0
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+interface eth-rt5
+ ip ospf network point-to-point
+ ip ospf area 2
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+router ospf
+ router-id 4.4.4.4
+ capability opaque
+ graceful-restart grace-period 120
+ graceful-restart helper-only
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_database.json b/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_database.json
new file mode 100644
index 0000000000..87b80414c9
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_database.json
@@ -0,0 +1,164 @@
+{
+ "routerId":"4.4.4.4",
+ "areas":{
+ "0.0.0.0":{
+ "routerLinkStates":[
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"2.2.2.2",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"3.3.3.3",
+ "numOfRouterLinks":7
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"4.4.4.4",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"6.6.6.6",
+ "numOfRouterLinks":3
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"1.1.1.1\/32"
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"5.5.5.5\/32"
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"7.7.7.7\/32"
+ },
+ {
+ "lsId":"10.0.1.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.1.0\/24"
+ },
+ {
+ "lsId":"10.0.5.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.5.0\/24"
+ },
+ {
+ "lsId":"10.0.6.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.6.0\/24"
+ }
+ ],
+ "asbrSummaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"2.2.2.2"
+ }
+ ]
+ },
+ "0.0.0.2":{
+ "routerLinkStates":[
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"4.4.4.4",
+ "numOfRouterLinks":2
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"5.5.5.5",
+ "numOfRouterLinks":3
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"1.1.1.1\/32"
+ },
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"2.2.2.2\/32"
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"3.3.3.3\/32"
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"4.4.4.4\/32"
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"6.6.6.6\/32"
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"7.7.7.7\/32"
+ },
+ {
+ "lsId":"10.0.1.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.1.0\/24"
+ },
+ {
+ "lsId":"10.0.2.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.2.0\/24"
+ },
+ {
+ "lsId":"10.0.3.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.3.0\/24"
+ },
+ {
+ "lsId":"10.0.4.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.4.0\/24"
+ },
+ {
+ "lsId":"10.0.6.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.6.0\/24"
+ }
+ ],
+ "asbrSummaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"4.4.4.4"
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"4.4.4.4"
+ }
+ ]
+ }
+ },
+ "asExternalLinkStates":[
+ {
+ "lsId":"172.16.1.0",
+ "advertisedRouter":"1.1.1.1",
+ "metricType":"E2",
+ "route":"172.16.1.0\/24",
+ "tag":0
+ },
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"6.6.6.6",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..2123ecb8da
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_neighbor.json
@@ -0,0 +1,18 @@
+{
+ "neighbors":{
+ "3.3.3.3":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.3.3",
+ "ifaceName":"eth-rt3:10.0.3.4"
+ }
+ ],
+ "5.5.5.5":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.5.5",
+ "ifaceName":"eth-rt5:10.0.5.4"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_route.json b/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_route.json
new file mode 100644
index 0000000000..04e318aef0
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_route.json
@@ -0,0 +1,202 @@
+{
+ "1.1.1.1\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "2.2.2.2\/32":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "3.3.3.3\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "4.4.4.4\/32":{
+ "routeType":"N",
+ "cost":0,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"lo"
+ }
+ ]
+ },
+ "5.5.5.5\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.5",
+ "via":"eth-rt5"
+ }
+ ]
+ },
+ "6.6.6.6\/32":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "7.7.7.7\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.1.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.2.0\/24":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.3.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.4.0\/24":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.5.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt5"
+ }
+ ]
+ },
+ "10.0.6.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "1.1.1.1":{
+ "routeType":"R ",
+ "cost":30,
+ "area":"0.0.0.0",
+ "IA":true,
+ "routerType":"asbr",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "2.2.2.2":{
+ "routeType":"R ",
+ "cost":20,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "6.6.6.6":{
+ "routeType":"R ",
+ "cost":20,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "172.16.1.0\/24":{
+ "routeType":"N E2",
+ "cost":30,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "192.168.1.0\/24":{
+ "routeType":"N E2",
+ "cost":30,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "via":"eth-rt3"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt4/show_ip_route.json b/tests/topotests/ospf_gr_topo1/rt4/show_ip_route.json
new file mode 100644
index 0000000000..8058f8f431
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt4/show_ip_route.json
@@ -0,0 +1,224 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"lo"
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "7.7.7.7\/32":[
+ {
+ "prefix":"7.7.7.7\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "172.16.1.0\/24":[
+ {
+ "prefix":"172.16.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "192.168.1.0\/24":[
+ {
+ "prefix":"192.168.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt4/zebra.conf b/tests/topotests/ospf_gr_topo1/rt4/zebra.conf
new file mode 100644
index 0000000000..f399b29f3f
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt4/zebra.conf
@@ -0,0 +1,23 @@
+password 1
+hostname rt4
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 4.4.4.4/32
+!
+interface eth-rt3
+ ip address 10.0.3.4/24
+!
+interface eth-rt5
+ ip address 10.0.5.4/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt5/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt5/ospfd.conf
new file mode 100644
index 0000000000..724af0e97c
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt5/ospfd.conf
@@ -0,0 +1,31 @@
+password 1
+hostname rt5
+log file ospfd.log
+log commands
+!
+debug ospf zebra
+debug ospf event
+debug ospf lsa
+debug ospf te
+debug ospf packet all
+debug ospf packet ls-update detail
+debug ospf ism
+debug ospf nsm
+debug ospf nssa
+debug ospf graceful-restart
+!
+interface lo
+ ip ospf area 2
+!
+interface eth-rt4
+ ip ospf network point-to-point
+ ip ospf area 2
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+router ospf
+ router-id 5.5.5.5
+ capability opaque
+ graceful-restart grace-period 120
+ graceful-restart helper-only
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_database.json b/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_database.json
new file mode 100644
index 0000000000..aeb8604473
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_database.json
@@ -0,0 +1,102 @@
+{
+ "routerId":"5.5.5.5",
+ "areas":{
+ "0.0.0.2":{
+ "routerLinkStates":[
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"4.4.4.4",
+ "numOfRouterLinks":2
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"5.5.5.5",
+ "numOfRouterLinks":3
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"1.1.1.1\/32"
+ },
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"2.2.2.2\/32"
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"3.3.3.3\/32"
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"4.4.4.4\/32"
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"6.6.6.6\/32"
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"7.7.7.7\/32"
+ },
+ {
+ "lsId":"10.0.1.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.1.0\/24"
+ },
+ {
+ "lsId":"10.0.2.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.2.0\/24"
+ },
+ {
+ "lsId":"10.0.3.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.3.0\/24"
+ },
+ {
+ "lsId":"10.0.4.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.4.0\/24"
+ },
+ {
+ "lsId":"10.0.6.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.6.0\/24"
+ }
+ ],
+ "asbrSummaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"4.4.4.4"
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"4.4.4.4"
+ }
+ ]
+ }
+ },
+ "asExternalLinkStates":[
+ {
+ "lsId":"172.16.1.0",
+ "advertisedRouter":"1.1.1.1",
+ "metricType":"E2",
+ "route":"172.16.1.0\/24",
+ "tag":0
+ },
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"6.6.6.6",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..6440b67698
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_neighbor.json
@@ -0,0 +1,11 @@
+{
+ "neighbors":{
+ "4.4.4.4":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.5.4",
+ "ifaceName":"eth-rt4:10.0.5.5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_route.json b/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_route.json
new file mode 100644
index 0000000000..e7f712ea6b
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_route.json
@@ -0,0 +1,203 @@
+{
+ "1.1.1.1\/32":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "2.2.2.2\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "3.3.3.3\/32":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "4.4.4.4\/32":{
+ "routeType":"N IA",
+ "cost":10,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "5.5.5.5\/32":{
+ "routeType":"N",
+ "cost":0,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"lo"
+ }
+ ]
+ },
+ "6.6.6.6\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "7.7.7.7\/32":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "10.0.1.0\/24":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "10.0.2.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "10.0.3.0\/24":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "10.0.4.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "10.0.5.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt4"
+ }
+ ]
+ },
+ "10.0.6.0\/24":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.2",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "1.1.1.1":{
+ "routeType":"R ",
+ "cost":40,
+ "area":"0.0.0.2",
+ "IA":true,
+ "routerType":"asbr",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "4.4.4.4":{
+ "routeType":"R ",
+ "cost":10,
+ "area":"0.0.0.2",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "6.6.6.6":{
+ "routeType":"R ",
+ "cost":30,
+ "area":"0.0.0.2",
+ "IA":true,
+ "routerType":"asbr",
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "172.16.1.0\/24":{
+ "routeType":"N E2",
+ "cost":40,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ },
+ "192.168.1.0\/24":{
+ "routeType":"N E2",
+ "cost":40,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "via":"eth-rt4"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt5/show_ip_route.json b/tests/topotests/ospf_gr_topo1/rt5/show_ip_route.json
new file mode 100644
index 0000000000..9896839440
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt5/show_ip_route.json
@@ -0,0 +1,225 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"lo"
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "7.7.7.7\/32":[
+ {
+ "prefix":"7.7.7.7\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "172.16.1.0\/24":[
+ {
+ "prefix":"172.16.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "192.168.1.0\/24":[
+ {
+ "prefix":"192.168.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.5.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt5/zebra.conf b/tests/topotests/ospf_gr_topo1/rt5/zebra.conf
new file mode 100644
index 0000000000..49a1c05a6d
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt5/zebra.conf
@@ -0,0 +1,20 @@
+password 1
+hostname rt5
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 5.5.5.5/32
+!
+interface eth-rt4
+ ip address 10.0.5.5/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt6/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt6/ospfd.conf
new file mode 100644
index 0000000000..0b9b83bcd2
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt6/ospfd.conf
@@ -0,0 +1,38 @@
+password 1
+hostname rt6
+log file ospfd.log
+log commands
+!
+debug ospf zebra
+debug ospf event
+debug ospf lsa
+debug ospf te
+debug ospf packet all
+debug ospf packet ls-update detail
+debug ospf ism
+debug ospf nsm
+debug ospf nssa
+debug ospf graceful-restart
+!
+interface lo
+ ip ospf area 0
+!
+interface eth-rt3
+ ip ospf network point-to-point
+ ip ospf area 0
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+interface eth-rt7
+ ip ospf network point-to-point
+ ip ospf area 3
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+router ospf
+ router-id 6.6.6.6
+ capability opaque
+ area 3 nssa
+ graceful-restart grace-period 120
+ graceful-restart helper-only
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_database.json b/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_database.json
new file mode 100644
index 0000000000..294b2c904e
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_database.json
@@ -0,0 +1,168 @@
+{
+ "routerId":"6.6.6.6",
+ "areas":{
+ "0.0.0.0":{
+ "routerLinkStates":[
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"2.2.2.2",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"3.3.3.3",
+ "numOfRouterLinks":7
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"4.4.4.4",
+ "numOfRouterLinks":3
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"6.6.6.6",
+ "numOfRouterLinks":3
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"1.1.1.1\/32"
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"5.5.5.5\/32"
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"7.7.7.7\/32"
+ },
+ {
+ "lsId":"10.0.1.0",
+ "advertisedRouter":"2.2.2.2",
+ "summaryAddress":"10.0.1.0\/24"
+ },
+ {
+ "lsId":"10.0.5.0",
+ "advertisedRouter":"4.4.4.4",
+ "summaryAddress":"10.0.5.0\/24"
+ },
+ {
+ "lsId":"10.0.6.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.6.0\/24"
+ }
+ ],
+ "asbrSummaryLinkStates":[
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"2.2.2.2"
+ }
+ ]
+ },
+ "0.0.0.3":{
+ "routerLinkStates":[
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"6.6.6.6",
+ "numOfRouterLinks":2
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"7.7.7.7",
+ "numOfRouterLinks":3
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"0.0.0.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"0.0.0.0\/0"
+ },
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"1.1.1.1\/32"
+ },
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"2.2.2.2\/32"
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"3.3.3.3\/32"
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"4.4.4.4\/32"
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"5.5.5.5\/32"
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"6.6.6.6\/32"
+ },
+ {
+ "lsId":"10.0.1.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.1.0\/24"
+ },
+ {
+ "lsId":"10.0.2.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.2.0\/24"
+ },
+ {
+ "lsId":"10.0.3.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.3.0\/24"
+ },
+ {
+ "lsId":"10.0.4.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.4.0\/24"
+ },
+ {
+ "lsId":"10.0.5.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.5.0\/24"
+ }
+ ],
+ "nssaExternalLinkStates":[
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"7.7.7.7",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+ }
+ },
+ "asExternalLinkStates":[
+ {
+ "lsId":"172.16.1.0",
+ "advertisedRouter":"1.1.1.1",
+ "metricType":"E2",
+ "route":"172.16.1.0\/24",
+ "tag":0
+ },
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"6.6.6.6",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..d815c23927
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_neighbor.json
@@ -0,0 +1,18 @@
+{
+ "neighbors":{
+ "3.3.3.3":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.4.3",
+ "ifaceName":"eth-rt3:10.0.4.6"
+ }
+ ],
+ "7.7.7.7":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.6.7",
+ "ifaceName":"eth-rt7:10.0.6.6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_route.json b/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_route.json
new file mode 100644
index 0000000000..d9009724d5
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_route.json
@@ -0,0 +1,214 @@
+{
+ "1.1.1.1\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "2.2.2.2\/32":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "3.3.3.3\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "4.4.4.4\/32":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "5.5.5.5\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "6.6.6.6\/32":{
+ "routeType":"N",
+ "cost":0,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"lo"
+ }
+ ]
+ },
+ "7.7.7.7\/32":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.7",
+ "via":"eth-rt7"
+ }
+ ]
+ },
+ "10.0.1.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.2.0\/24":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.3.0\/24":{
+ "routeType":"N",
+ "cost":20,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.4.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.5.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.0",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "10.0.6.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt7"
+ }
+ ]
+ },
+ "1.1.1.1":{
+ "routeType":"R ",
+ "cost":30,
+ "area":"0.0.0.0",
+ "IA":true,
+ "routerType":"asbr",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "2.2.2.2":{
+ "routeType":"R ",
+ "cost":20,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "4.4.4.4":{
+ "routeType":"R ",
+ "cost":20,
+ "area":"0.0.0.0",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "7.7.7.7":{
+ "routeType":"R ",
+ "cost":10,
+ "area":"0.0.0.3",
+ "routerType":"asbr",
+ "nexthops":[
+ {
+ "ip":"10.0.6.7",
+ "via":"eth-rt7"
+ }
+ ]
+ },
+ "172.16.1.0\/24":{
+ "routeType":"N E2",
+ "cost":30,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "via":"eth-rt3"
+ }
+ ]
+ },
+ "192.168.1.0\/24":{
+ "routeType":"N E2",
+ "cost":10,
+ "nexthops":[
+ {
+ "ip":"10.0.6.7",
+ "via":"eth-rt7"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt6/show_ip_route.json b/tests/topotests/ospf_gr_topo1/rt6/show_ip_route.json
new file mode 100644
index 0000000000..dd95f1fab1
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt6/show_ip_route.json
@@ -0,0 +1,224 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"lo"
+ }
+ ]
+ }
+ ],
+ "7.7.7.7\/32":[
+ {
+ "prefix":"7.7.7.7\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.6.7",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt7"
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt7"
+ }
+ ]
+ }
+ ],
+ "172.16.1.0\/24":[
+ {
+ "prefix":"172.16.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3"
+ }
+ ]
+ }
+ ],
+ "192.168.1.0\/24":[
+ {
+ "prefix":"192.168.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.6.7",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt7"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt6/zebra.conf b/tests/topotests/ospf_gr_topo1/rt6/zebra.conf
new file mode 100644
index 0000000000..d6a8f52b3a
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt6/zebra.conf
@@ -0,0 +1,23 @@
+password 1
+hostname rt6
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 6.6.6.6/32
+!
+interface eth-rt3
+ ip address 10.0.4.6/24
+!
+interface eth-rt7
+ ip address 10.0.6.6/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt7/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt7/ospfd.conf
new file mode 100644
index 0000000000..49db254410
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt7/ospfd.conf
@@ -0,0 +1,33 @@
+password 1
+hostname rt7
+log file ospfd.log
+log commands
+!
+debug ospf zebra
+debug ospf event
+debug ospf lsa
+debug ospf te
+debug ospf packet all
+debug ospf packet ls-update detail
+debug ospf ism
+debug ospf nsm
+debug ospf nssa
+debug ospf graceful-restart
+!
+interface lo
+ ip ospf area 3
+!
+interface eth-rt6
+ ip ospf network point-to-point
+ ip ospf area 3
+ ip ospf hello-interval 3
+ ip ospf dead-interval 9
+!
+router ospf
+ router-id 7.7.7.7
+ capability opaque
+ redistribute connected
+ area 3 nssa
+ graceful-restart grace-period 120
+ graceful-restart helper-only
+!
diff --git a/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_database.json b/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_database.json
new file mode 100644
index 0000000000..4916fba9d4
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_database.json
@@ -0,0 +1,99 @@
+{
+ "routerId":"7.7.7.7",
+ "areas":{
+ "0.0.0.3":{
+ "routerLinkStates":[
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"6.6.6.6",
+ "numOfRouterLinks":2
+ },
+ {
+ "lsId":"7.7.7.7",
+ "advertisedRouter":"7.7.7.7",
+ "numOfRouterLinks":3
+ }
+ ],
+ "summaryLinkStates":[
+ {
+ "lsId":"0.0.0.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"0.0.0.0\/0"
+ },
+ {
+ "lsId":"1.1.1.1",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"1.1.1.1\/32"
+ },
+ {
+ "lsId":"2.2.2.2",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"2.2.2.2\/32"
+ },
+ {
+ "lsId":"3.3.3.3",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"3.3.3.3\/32"
+ },
+ {
+ "lsId":"4.4.4.4",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"4.4.4.4\/32"
+ },
+ {
+ "lsId":"5.5.5.5",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"5.5.5.5\/32"
+ },
+ {
+ "lsId":"6.6.6.6",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"6.6.6.6\/32"
+ },
+ {
+ "lsId":"10.0.1.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.1.0\/24"
+ },
+ {
+ "lsId":"10.0.2.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.2.0\/24"
+ },
+ {
+ "lsId":"10.0.3.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.3.0\/24"
+ },
+ {
+ "lsId":"10.0.4.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.4.0\/24"
+ },
+ {
+ "lsId":"10.0.5.0",
+ "advertisedRouter":"6.6.6.6",
+ "summaryAddress":"10.0.5.0\/24"
+ }
+ ],
+ "nssaExternalLinkStates":[
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"7.7.7.7",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+ }
+ },
+ "asExternalLinkStates":[
+ {
+ "lsId":"192.168.1.0",
+ "advertisedRouter":"7.7.7.7",
+ "metricType":"E2",
+ "route":"192.168.1.0\/24",
+ "tag":0
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_neighbor.json
new file mode 100644
index 0000000000..2254aea9a6
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_neighbor.json
@@ -0,0 +1,11 @@
+{
+ "neighbors":{
+ "6.6.6.6":[
+ {
+ "state":"Full\/DROther",
+ "address":"10.0.6.6",
+ "ifaceName":"eth-rt6:10.0.6.7"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_route.json b/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_route.json
new file mode 100644
index 0000000000..89bad320bb
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_route.json
@@ -0,0 +1,168 @@
+{
+ "0.0.0.0\/0":{
+ "routeType":"N IA",
+ "cost":11,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "1.1.1.1\/32":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "2.2.2.2\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "3.3.3.3\/32":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "4.4.4.4\/32":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "5.5.5.5\/32":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "6.6.6.6\/32":{
+ "routeType":"N IA",
+ "cost":10,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "7.7.7.7\/32":{
+ "routeType":"N",
+ "cost":0,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"lo"
+ }
+ ]
+ },
+ "10.0.1.0\/24":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "10.0.2.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "10.0.3.0\/24":{
+ "routeType":"N IA",
+ "cost":30,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "10.0.4.0\/24":{
+ "routeType":"N IA",
+ "cost":20,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "10.0.5.0\/24":{
+ "routeType":"N IA",
+ "cost":40,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ },
+ "10.0.6.0\/24":{
+ "routeType":"N",
+ "cost":10,
+ "area":"0.0.0.3",
+ "nexthops":[
+ {
+ "ip":" ",
+ "directly attached to":"eth-rt6"
+ }
+ ]
+ },
+ "6.6.6.6":{
+ "routeType":"R ",
+ "cost":10,
+ "area":"0.0.0.3",
+ "routerType":"abr",
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "via":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt7/show_ip_route.json b/tests/topotests/ospf_gr_topo1/rt7/show_ip_route.json
new file mode 100644
index 0000000000..0fb906b76b
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt7/show_ip_route.json
@@ -0,0 +1,210 @@
+{
+ "0.0.0.0\/0":[
+ {
+ "prefix":"0.0.0.0\/0",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":11,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "7.7.7.7\/32":[
+ {
+ "prefix":"7.7.7.7\/32",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":0,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"lo"
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.6.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"ospf",
+ "distance":110,
+ "metric":10,
+ "nexthops":[
+ {
+ "directlyConnected":true,
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ospf_gr_topo1/rt7/zebra.conf b/tests/topotests/ospf_gr_topo1/rt7/zebra.conf
new file mode 100644
index 0000000000..c481e4532b
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/rt7/zebra.conf
@@ -0,0 +1,23 @@
+password 1
+hostname rt7
+log file zebra.log
+log commands
+!
+debug zebra event
+debug zebra packet
+debug zebra rib
+debug zebra kernel
+!
+interface lo
+ ip address 7.7.7.7/32
+!
+interface stub1
+ ip address 192.168.1.1/24
+!
+interface eth-rt6
+ ip address 10.0.6.7/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
new file mode 100755
index 0000000000..0507c2d516
--- /dev/null
+++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
@@ -0,0 +1,393 @@
+#!/usr/bin/env python
+
+#
+# test_ospf_gr_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# 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.
+#
+
+"""
+test_ospf_gr_topo1.py:
+
+ +---------+
+ | RT1 |
+ | 1.1.1.1 |
+ +---------+
+ |eth-rt2
+ |
+ |10.0.1.0/24
+ |
+ |eth-rt1
+ +---------+
+ | RT2 |
+ | 2.2.2.2 |
+ +---------+
+ |eth-rt3
+ |
+ |10.0.2.0/24
+ |
+ |eth-rt2
+ +---------+
+ | RT3 |
+ | 3.3.3.3 |
+ +---------+
+ eth-rt4| |eth-rt6
+ | |
+ 10.0.3.0/24 | | 10.0.4.0/24
+ +---------+ +--------+
+ | |
+ |eth-rt3 |eth-rt3
+ +---------+ +---------+
+ | RT4 | | RT6 |
+ | 4.4.4.4 | | 6.6.6.6 |
+ +---------+ +---------+
+ |eth-rt5 |eth-rt7
+ | |
+ |10.0.5.0/24 |10.0.6.0/24
+ | |
+ |eth-rt4 |eth-rt6
+ +---------+ +---------+
+ | RT5 | | RT7 |
+ | 5.5.5.5 | | 7.7.7.7 |
+ +---------+ +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+import tempfile
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# 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
+from lib.common_config import (
+ kill_router_daemons,
+ start_router_daemons,
+)
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+pytestmark = [pytest.mark.ospfd]
+
+# Global multi-dimensional dictionary containing all expected outputs
+outputs = {}
+
+
+class TemplateTopo(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ #
+ # Define FRR Routers
+ #
+ for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt2")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt1")
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["rt1"], nodeif="stub1")
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt3")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt2")
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt4")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt3")
+
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt6")
+ switch.add_link(tgen.gears["rt6"], nodeif="eth-rt3")
+
+ switch = tgen.add_switch("s6")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt5")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt4")
+
+ switch = tgen.add_switch("s7")
+ switch.add_link(tgen.gears["rt6"], nodeif="eth-rt7")
+ switch.add_link(tgen.gears["rt7"], nodeif="eth-rt6")
+
+ switch = tgen.add_switch("s8")
+ switch.add_link(tgen.gears["rt7"], nodeif="stub1")
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+
+def router_compare_json_output(rname, command, reference, tries):
+ "Compare router JSON output"
+
+ logger.info('Comparing router "%s" "%s" output', rname, command)
+
+ tgen = get_topogen()
+ filename = "{}/{}/{}".format(CWD, rname, reference)
+ expected = json.loads(open(filename).read())
+
+ test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=tries, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+
+def check_routers(initial_convergence=False, exiting=None, restarting=None):
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+ # Check the RIB first, which should be preserved across restarts in
+ # all routers of the routing domain.
+ if initial_convergence == True:
+ tries = 240
+ else:
+ tries = 1
+ router_compare_json_output(
+ rname, "show ip route ospf json", "show_ip_route.json", tries
+ )
+
+ # Check that all adjacencies are up and running (except when there's
+ # an OSPF instance that is shutting down).
+ if exiting == None:
+ tries = 240
+ router_compare_json_output(
+ rname, "show ip ospf neighbor json", "show_ip_ospf_neighbor.json", tries
+ )
+
+ # Check the OSPF RIB and LSDB.
+ # In the restarting router, wait up to one minute for the LSDB to converge.
+ if exiting != rname:
+ if initial_convergence == True or restarting == rname:
+ tries = 240
+ else:
+ tries = 1
+ router_compare_json_output(
+ rname, "show ip ospf database json", "show_ip_ospf_database.json", tries
+ )
+ router_compare_json_output(
+ rname, "show ip ospf route json", "show_ip_ospf_route.json", tries
+ )
+
+
+#
+# Test initial network convergence
+#
+def test_initial_convergence():
+ logger.info("Test: verify initial network convergence")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ check_routers(initial_convergence=True)
+
+
+#
+# Test rt1 performing a graceful restart
+#
+def test_gr_rt1():
+ logger.info("Test: verify rt1 performing a graceful restart")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.net["rt1"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
+ sleep(3)
+ kill_router_daemons(tgen, "rt1", ["ospfd"], save_config=False)
+ check_routers(exiting="rt1")
+
+ start_router_daemons(tgen, "rt1", ["ospfd"])
+ check_routers(restarting="rt1")
+
+
+#
+# Test rt2 performing a graceful restart
+#
+def test_gr_rt2():
+ logger.info("Test: verify rt2 performing a graceful restart")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.net["rt2"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
+ sleep(3)
+ kill_router_daemons(tgen, "rt2", ["ospfd"], save_config=False)
+ check_routers(exiting="rt2")
+
+ start_router_daemons(tgen, "rt2", ["ospfd"])
+ check_routers(restarting="rt2")
+
+
+#
+# Test rt3 performing a graceful restart
+#
+def test_gr_rt3():
+ logger.info("Test: verify rt3 performing a graceful restart")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.net["rt3"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
+ sleep(3)
+ kill_router_daemons(tgen, "rt3", ["ospfd"], save_config=False)
+ check_routers(exiting="rt3")
+
+ start_router_daemons(tgen, "rt3", ["ospfd"])
+ check_routers(restarting="rt3")
+
+
+#
+# Test rt4 performing a graceful restart
+#
+def test_gr_rt4():
+ logger.info("Test: verify rt4 performing a graceful restart")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.net["rt4"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
+ sleep(3)
+ kill_router_daemons(tgen, "rt4", ["ospfd"], save_config=False)
+ check_routers(exiting="rt4")
+
+ start_router_daemons(tgen, "rt4", ["ospfd"])
+ check_routers(restarting="rt4")
+
+
+#
+# Test rt5 performing a graceful restart
+#
+def test_gr_rt5():
+ logger.info("Test: verify rt5 performing a graceful restart")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.net["rt5"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
+ sleep(3)
+ kill_router_daemons(tgen, "rt5", ["ospfd"], save_config=False)
+ check_routers(exiting="rt5")
+
+ start_router_daemons(tgen, "rt5", ["ospfd"])
+ check_routers(restarting="rt5")
+
+
+#
+# Test rt6 performing a graceful restart
+#
+def test_gr_rt6():
+ logger.info("Test: verify rt6 performing a graceful restart")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.net["rt6"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
+ sleep(3)
+ kill_router_daemons(tgen, "rt6", ["ospfd"], save_config=False)
+ check_routers(exiting="rt6")
+
+ start_router_daemons(tgen, "rt6", ["ospfd"])
+ check_routers(restarting="rt6")
+
+
+#
+# Test rt7 performing a graceful restart
+#
+def test_gr_rt7():
+ logger.info("Test: verify rt7 performing a graceful restart")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.net["rt7"].cmd('vtysh -c "graceful-restart prepare ip ospf"')
+ sleep(3)
+ kill_router_daemons(tgen, "rt7", ["ospfd"], save_config=False)
+ check_routers(exiting="rt7")
+
+ start_router_daemons(tgen, "rt7", ["ospfd"])
+ check_routers(restarting="rt7")
+
+
+# Memory leak test template
+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))