summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.git-blame-ignore-revs1
-rw-r--r--doc/user/bgp.rst32
-rw-r--r--pathd/path_cli.c2
-rw-r--r--pbrd/pbr_nht.c56
-rw-r--r--tests/topotests/all-protocol-startup/test_all_protocol_startup.py24
-rw-r--r--tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py3
-rw-r--r--tests/topotests/bgp-basic-functionality-topo1/test_bgp_basic_functionality.py30
-rw-r--r--tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py34
-rw-r--r--tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py34
-rw-r--r--tests/topotests/bgp-evpn-mh/test_evpn_mh.py21
-rwxr-xr-xtests/topotests/bgp-evpn-vxlan_topo1/test_bgp_evpn_vxlan.py6
-rw-r--r--tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py7
-rw-r--r--tests/topotests/bgp-route-map/test_route_map_topo1.py33
-rw-r--r--tests/topotests/bgp-route-map/test_route_map_topo2.py64
-rw-r--r--tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py18
-rw-r--r--tests/topotests/bgp_features/test_bgp_features.py254
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py158
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py31
-rw-r--r--tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py12
-rw-r--r--tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py38
-rw-r--r--tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py6
-rw-r--r--tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py53
-rw-r--r--tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py17
-rw-r--r--tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py2
-rw-r--r--tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py7
-rwxr-xr-xtests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py343
-rwxr-xr-xtests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py378
-rw-r--r--tests/topotests/ldp-topo1/test_ldp_topo1.py8
-rw-r--r--tests/topotests/lib/bgp.py101
-rw-r--r--tests/topotests/lib/common_config.py96
-rw-r--r--tests/topotests/lib/ospf.py12
-rwxr-xr-xtests/topotests/lib/test/test_json.py229
-rw-r--r--tests/topotests/lib/topogen.py4
-rw-r--r--tests/topotests/lib/topojson.py14
-rw-r--r--tests/topotests/lib/topotest.py75
-rw-r--r--tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py6
-rw-r--r--tests/topotests/ospf-topo1/test_ospf_topo1.py29
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py12
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py609
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py14
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_single_area.py253
-rw-r--r--tests/topotests/rip-topo1/test_rip_topo1.py8
-rw-r--r--tests/topotests/ripng-topo1/test_ripng_topo1.py8
-rw-r--r--tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json157
-rw-r--r--tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json363
-rw-r--r--tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json428
-rw-r--r--tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py1261
-rw-r--r--tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py1711
-rw-r--r--tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py994
-rw-r--r--tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json157
-rw-r--r--tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json371
-rw-r--r--tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json189
-rw-r--r--tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json428
-rw-r--r--tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py1083
-rw-r--r--tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py1974
-rw-r--r--tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py875
-rw-r--r--tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py991
-rw-r--r--tests/topotests/zebra_netlink/test_zebra_netlink.py7
-rw-r--r--zebra/connected.c4
-rw-r--r--zebra/kernel_socket.c4
-rw-r--r--zebra/redistribute.c2
-rw-r--r--zebra/rib.h2
-rw-r--r--zebra/rt_netlink.c6
-rw-r--r--zebra/zapi_msg.c2
-rw-r--r--zebra/zebra_rib.c15
65 files changed, 12977 insertions, 1189 deletions
diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs
index 61bc0ade65..c3a0fdedf0 100644
--- a/.git-blame-ignore-revs
+++ b/.git-blame-ignore-revs
@@ -2,6 +2,7 @@
# git blame --ignore-revs-file .git-blame-ignore-revs <...>
# or to make it permanent
# git config blame.ignoreRevsFile .git-blame-ignore-revs
+9fa6ec14737b94fdfb41539d96c7e4f84f3514b6
701a01920eee5431d2052aad92aefbdf50ac2139
bf2394f08bdc91a6cbd3784a1bfa3af3247bb06f
0157c327715ca367d13b7f02b2981f3484ccdeeb
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 0782461670..e0e16aaeeb 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -798,6 +798,38 @@ The following functionality is provided by graceful restart:
<--------------------------------------------------------------------->
+.. _bgp-GR-preserve-forwarding-state:
+
+BGP-GR Preserve-Forwarding State
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+BGP OPEN message carrying optional capabilities for Graceful Restart has
+8 bit “Flags for Address Family” for given AFI and SAFI. This field contains
+bit flags relating to routes that were advertised with the given AFI and SAFI.
+
+.. code-block:: frr
+
+ 0 1 2 3 4 5 6 7
+ +-+-+-+-+-+-+-+-+
+ |F| Reserved |
+ +-+-+-+-+-+-+-+-+
+
+The most significant bit is defined as the Forwarding State (F) bit, which
+can be used to indicate whether the forwarding state for routes that were
+advertised with the given AFI and SAFI has indeed been preserved during the
+previous BGP restart. When set (value 1), the bit indicates that the
+forwarding state has been preserved.
+The remaining bits are reserved and MUST be set to zero by the sender and
+ignored by the receiver.
+
+.. index:: bgp graceful-restart preserve-fw-state
+.. clicmd:: bgp graceful-restart preserve-fw-state
+
+FRR gives us the option to enable/disable the "F" flag using this specific
+vty command. However, it doesn't have the option to enable/disable
+this flag only for specific AFI/SAFI i.e. when this command is used, it
+applied to all the supported AFI/SAFI combinations for this peer.
+
.. _bgp-end-of-rib-message:
End-of-RIB (EOR) message
diff --git a/pathd/path_cli.c b/pathd/path_cli.c
index a55e6ba406..8beb428135 100644
--- a/pathd/path_cli.c
+++ b/pathd/path_cli.c
@@ -550,7 +550,7 @@ DEFPY_NOSH(
"Symbolic Name\n"
"Dynamic Path\n")
{
- char xpath[XPATH_CANDIDATE_BASELEN];
+ char xpath[XPATH_MAXLEN + XPATH_CANDIDATE_BASELEN];
int ret;
snprintf(xpath, sizeof(xpath), "%s/candidate-path[preference='%s']",
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index ce7780ed49..8fd7ac9e3c 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -719,8 +719,51 @@ pbr_nht_individual_nexthop_gw_update(struct pbr_nexthop_cache *pnhc,
{
bool is_valid = pnhc->valid;
- if (!pnhi->nhr) /* It doesn't care about non-nexthop updates */
+ /*
+ * If we have an interface down event, let's note that
+ * it is happening and find all the nexthops that depend
+ * on that interface. As that if we have an interface
+ * flapping fast enough it means that zebra might turn
+ * those nexthop tracking events into a no-update
+ * So let's search and do the right thing on the
+ * interface event.
+ */
+ if (!pnhi->nhr && pnhi->ifp) {
+ struct connected *connected;
+ struct listnode *node;
+ struct prefix p;
+
+ switch (pnhc->nexthop.type) {
+ case NEXTHOP_TYPE_BLACKHOLE:
+ goto done;
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ is_valid = if_is_up(pnhi->ifp);
+ goto done;
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ p.family = AF_INET;
+ p.prefixlen = IPV4_MAX_BITLEN;
+ p.u.prefix4 = pnhc->nexthop.gate.ipv4;
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ p.family = AF_INET6;
+ p.prefixlen = IPV6_MAX_BITLEN;
+ memcpy(&p.u.prefix6, &pnhc->nexthop.gate.ipv6,
+ sizeof(struct in6_addr));
+ break;
+ }
+
+ FOR_ALL_INTERFACES_ADDRESSES (pnhi->ifp, connected, node) {
+ if (prefix_match(connected->address, &p)) {
+ is_valid = if_is_up(pnhi->ifp);
+ break;
+ }
+ }
goto done;
+ }
switch (pnhi->nhr->prefix.family) {
case AF_INET:
@@ -983,7 +1026,6 @@ static void pbr_nht_nexthop_vrf_handle(struct hash_bucket *b, void *data)
struct pbr_vrf *pbr_vrf = data;
struct pbr_nht_individual pnhi = {};
- zlog_debug("pnhgc iterating");
hash_iterate(pnhgc->nhh, pbr_nht_clear_looked_at, NULL);
memset(&pnhi, 0, sizeof(pnhi));
pnhi.pbr_vrf = pbr_vrf;
@@ -1097,6 +1139,7 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
{
struct pbr_nexthop_group_cache *pnhgc = b->data;
struct pbr_nht_individual pnhi = {};
+ struct nexthop_group nhg = {};
bool old_valid;
old_valid = pnhgc->valid;
@@ -1111,6 +1154,15 @@ static void pbr_nht_nexthop_interface_update_lookup(struct hash_bucket *b,
*/
pnhgc->valid = pnhi.valid;
+ pbr_nexthop_group_cache_to_nexthop_group(&nhg, pnhgc);
+
+ if (pnhgc->valid)
+ pbr_nht_install_nexthop_group(pnhgc, nhg);
+ else
+ pbr_nht_uninstall_nexthop_group(pnhgc, nhg, 0);
+
+ nexthops_free(nhg.nexthop);
+
if (old_valid != pnhgc->valid)
pbr_map_check_nh_group_change(pnhgc->name);
}
diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
index 08378d9b58..ab9358408e 100644
--- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
+++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
@@ -1016,6 +1016,7 @@ def test_bgp_ipv6_summary():
# For debugging after starting FRR daemons, uncomment the next line
# CLI(net)
+
def test_nht():
print("\n\n**** Test that nexthop tracking is at least nominally working ****\n")
@@ -1026,13 +1027,16 @@ def test_nht():
expected = open(nhtFile).read().rstrip()
expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
- actual = (net["r%s" %i].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip())
+ actual = net["r%s" % i].cmd('vtysh -c "show ip nht" 2> /dev/null').rstrip()
actual = re.sub(r"fd [0-9][0-9]", "fd XX", actual)
actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
- diff = topotest.get_textdiff(actual, expected,
- title1="Actual `show ip nht`",
- title2="Expected `show ip nht`")
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="Actual `show ip nht`",
+ title2="Expected `show ip nht`",
+ )
if diff:
assert 0, "r%s failed ip nht check:\n%s\n" % (i, diff)
@@ -1043,19 +1047,23 @@ def test_nht():
expected = open(nhtFile).read().rstrip()
expected = ("\n".join(expected.splitlines()) + "\n").splitlines(1)
- actual = (net["r%s" %i].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip())
+ actual = net["r%s" % i].cmd('vtysh -c "show ipv6 nht" 2> /dev/null').rstrip()
actual = re.sub(r"fd [0-9][0-9]", "fd XX", actual)
actual = ("\n".join(actual.splitlines()) + "\n").splitlines(1)
- diff = topotest.get_textdiff(actual, expected,
- title1="Actual `show ip nht`",
- title2="Expected `show ip nht`")
+ diff = topotest.get_textdiff(
+ actual,
+ expected,
+ title1="Actual `show ip nht`",
+ title2="Expected `show ip nht`",
+ )
if diff:
assert 0, "r%s failed ipv6 nht check:\n%s\n" % (i, diff)
else:
print("show ipv6 nht is ok\n")
+
def test_bgp_ipv4():
global fatal_error
global net
diff --git a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
index 595132214b..98a5033f53 100644
--- a/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
+++ b/tests/topotests/bfd-bgp-cbit-topo3/test_bfd_bgp_cbit_topo3.py
@@ -74,7 +74,8 @@ def setup_module(mod):
for rname, router in router_list.items():
router.load_config(
- TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)),
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, "{}/zebra.conf".format(rname)),
)
router.load_config(
TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
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 b3b7256ac4..b701a0d61e 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
@@ -282,10 +282,26 @@ def test_BGP_config_with_invalid_ASN_p2(request):
# Api call to modify AS number
input_dict = {
- "r1": {"bgp": {"local_as": 0,}},
- "r2": {"bgp": {"local_as": 0,}},
- "r3": {"bgp": {"local_as": 0,}},
- "r4": {"bgp": {"local_as": 64000,}},
+ "r1": {
+ "bgp": {
+ "local_as": 0,
+ }
+ },
+ "r2": {
+ "bgp": {
+ "local_as": 0,
+ }
+ },
+ "r3": {
+ "bgp": {
+ "local_as": 0,
+ }
+ },
+ "r4": {
+ "bgp": {
+ "local_as": 64000,
+ }
+ },
}
result = modify_as_number(tgen, topo, input_dict)
try:
@@ -819,7 +835,11 @@ def test_bgp_with_loopback_interface(request):
# Adding ['source_link'] = 'lo' key:value pair
topo["routers"][routerN]["bgp"]["address_family"]["ipv4"]["unicast"][
"neighbor"
- ][bgp_neighbor]["dest_link"] = {"lo": {"source_link": "lo",}}
+ ][bgp_neighbor]["dest_link"] = {
+ "lo": {
+ "source_link": "lo",
+ }
+ }
# Creating configuration from JSON
build_config_from_json(tgen, topo)
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
index 54a3c699f3..353df0684b 100644
--- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
@@ -273,8 +273,20 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
"r3": {
"bgp": {
"address_family": {
- "ipv4": {"unicast": {"maximum_paths": {"ebgp": ecmp_num,}}},
- "ipv6": {"unicast": {"maximum_paths": {"ebgp": ecmp_num,}}},
+ "ipv4": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": ecmp_num,
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": ecmp_num,
+ }
+ }
+ },
}
}
}
@@ -303,7 +315,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
input_dict_1,
next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)],
protocol=protocol,
- count_only=True
+ count_only=True,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -312,9 +324,9 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
write_test_footer(tc_name)
-
+@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"])
@pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
-def test_ecmp_after_clear_bgp(request, test_type):
+def test_ecmp_after_clear_bgp(request, ecmp_num, test_type):
""" Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""
tc_name = request.node.name
@@ -337,7 +349,7 @@ def test_ecmp_after_clear_bgp(request, test_type):
addr_type,
dut,
input_dict_1,
- next_hop=NEXT_HOPS[addr_type],
+ next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
protocol=protocol,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -360,7 +372,7 @@ def test_ecmp_after_clear_bgp(request, test_type):
addr_type,
dut,
input_dict_1,
- next_hop=NEXT_HOPS[addr_type],
+ next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
protocol=protocol,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -371,8 +383,8 @@ def test_ecmp_after_clear_bgp(request, test_type):
def test_ecmp_remove_redistribute_static(request):
- """ Verify routes are cleared from BGP and RIB table of DUT when
- redistribute static configuration is removed."""
+ """Verify routes are cleared from BGP and RIB table of DUT when
+ redistribute static configuration is removed."""
tc_name = request.node.name
write_test_header(tc_name)
@@ -481,8 +493,8 @@ def test_ecmp_remove_redistribute_static(request):
@pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
def test_ecmp_shut_bgp_neighbor(request, test_type):
- """ Shut BGP neigbors one by one and verify BGP and routing table updated
- accordingly in DUT """
+ """Shut BGP neigbors one by one and verify BGP and routing table updated
+ accordingly in DUT"""
tc_name = request.node.name
write_test_header(tc_name)
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
index 73724ac069..2f73bdb1b8 100644
--- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
@@ -274,8 +274,20 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
"r3": {
"bgp": {
"address_family": {
- "ipv4": {"unicast": {"maximum_paths": {"ibgp": ecmp_num,}}},
- "ipv6": {"unicast": {"maximum_paths": {"ibgp": ecmp_num,}}},
+ "ipv4": {
+ "unicast": {
+ "maximum_paths": {
+ "ibgp": ecmp_num,
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "maximum_paths": {
+ "ibgp": ecmp_num,
+ }
+ }
+ },
}
}
}
@@ -304,7 +316,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
input_dict_1,
next_hop=NEXT_HOPS[addr_type][: int(ecmp_num)],
protocol=protocol,
- count_only=True
+ count_only=True,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -313,9 +325,9 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
write_test_footer(tc_name)
-
+@pytest.mark.parametrize("ecmp_num", ["8", "16", "32"])
@pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
-def test_ecmp_after_clear_bgp(request, test_type):
+def test_ecmp_after_clear_bgp(request, ecmp_num, test_type):
""" Verify BGP table and RIB in DUT after clear BGP routes and neighbors"""
tc_name = request.node.name
@@ -338,7 +350,7 @@ def test_ecmp_after_clear_bgp(request, test_type):
addr_type,
dut,
input_dict_1,
- next_hop=NEXT_HOPS[addr_type],
+ next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
protocol=protocol,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -361,7 +373,7 @@ def test_ecmp_after_clear_bgp(request, test_type):
addr_type,
dut,
input_dict_1,
- next_hop=NEXT_HOPS[addr_type],
+ next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
protocol=protocol,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
@@ -372,8 +384,8 @@ def test_ecmp_after_clear_bgp(request, test_type):
def test_ecmp_remove_redistribute_static(request):
- """ Verify routes are cleared from BGP and RIB table of DUT when
- redistribute static configuration is removed."""
+ """Verify routes are cleared from BGP and RIB table of DUT when
+ redistribute static configuration is removed."""
tc_name = request.node.name
write_test_header(tc_name)
@@ -482,8 +494,8 @@ def test_ecmp_remove_redistribute_static(request):
@pytest.mark.parametrize("test_type", ["redist_static", "advertise_nw"])
def test_ecmp_shut_bgp_neighbor(request, test_type):
- """ Shut BGP neigbors one by one and verify BGP and routing table updated
- accordingly in DUT """
+ """Shut BGP neigbors one by one and verify BGP and routing table updated
+ accordingly in DUT"""
tc_name = request.node.name
write_test_header(tc_name)
diff --git a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
index 4c56d1a02d..6a24684649 100644
--- a/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
+++ b/tests/topotests/bgp-evpn-mh/test_evpn_mh.py
@@ -658,10 +658,11 @@ def test_evpn_mac():
assertmsg = '"{}" remote MAC content incorrect'.format(tor.name)
assert result is None, assertmsg
+
def check_df_role(dut, esi, role):
- '''
+ """
Return error string if the df role on the dut is different
- '''
+ """
es_json = dut.vtysh_cmd("show evpn es %s json" % esi)
es = json.loads(es_json)
@@ -676,12 +677,13 @@ def check_df_role(dut, esi, role):
return None
+
def test_evpn_df():
- '''
+ """
1. Check the DF role on all the PEs on rack-1.
2. Increase the DF preference on the non-DF and check if it becomes
the DF winner.
- '''
+ """
tgen = get_topogen()
@@ -720,10 +722,11 @@ def test_evpn_df():
# tgen.mininet_cli()
+
def check_protodown_rc(dut, protodown_rc):
- '''
+ """
check if specified protodown reason code is set
- '''
+ """
out = dut.vtysh_cmd("show evpn json")
@@ -739,13 +742,14 @@ def check_protodown_rc(dut, protodown_rc):
return None
+
def test_evpn_uplink_tracking():
- '''
+ """
1. Wait for access ports to come out of startup-delay
2. disable uplinks and check if access ports have been protodowned
3. enable uplinks and check if access ports have been moved out
of protodown
- '''
+ """
tgen = get_topogen()
@@ -778,6 +782,7 @@ def test_evpn_uplink_tracking():
assertmsg = '"{}" protodown rc incorrect'.format(dut_name)
assert result is None, assertmsg
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
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 5098808d55..9a38158b2b 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
@@ -310,8 +310,10 @@ def ip_learn_test(tgen, host, local, remote, ip_addr):
assertmsg = "local learned mac wrong type: {} ".format(mac_type)
assert mac_type == "local", assertmsg
- assertmsg = "learned address mismatch with configured address host: {} learned: {}".format(
- ip_addr, learned_ip
+ assertmsg = (
+ "learned address mismatch with configured address host: {} learned: {}".format(
+ ip_addr, learned_ip
+ )
)
assert ip_addr == learned_ip, assertmsg
diff --git a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
index 607b036c6a..a9541a55c5 100644
--- a/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
+++ b/tests/topotests/bgp-path-attributes-topo1/test_bgp_path_attributes.py
@@ -238,9 +238,10 @@ def test_next_hop_attribute(request):
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert result is not True, (
- "Testcase {} : Failed \n Error: "
- "{} routes are not present in RIB".format(addr_type, tc_name)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Error: " "{} routes are not present in RIB".format(
+ addr_type, tc_name
)
# Configure next-hop-self to bgp neighbor
diff --git a/tests/topotests/bgp-route-map/test_route_map_topo1.py b/tests/topotests/bgp-route-map/test_route_map_topo1.py
index 1aa951edaa..0158e24d31 100644
--- a/tests/topotests/bgp-route-map/test_route_map_topo1.py
+++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py
@@ -807,7 +807,9 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request):
"prefix_lists": "pf_list_2_{}".format(addr_type)
}
},
- "set": {"locPrf": 150,},
+ "set": {
+ "locPrf": 150,
+ },
},
{
"action": "permit",
@@ -906,7 +908,17 @@ def test_route_map_multiple_seq_different_match_set_clause_p0(request):
dut = "r3"
protocol = "bgp"
input_dict = {
- "r3": {"route_maps": {"rmap_match_pf_list1": [{"set": {"metric": 50,}}],}}
+ "r3": {
+ "route_maps": {
+ "rmap_match_pf_list1": [
+ {
+ "set": {
+ "metric": 50,
+ }
+ }
+ ],
+ }
+ }
}
static_routes = [NETWORK[adt][0]]
@@ -1093,7 +1105,14 @@ def test_route_map_set_only_no_match_p0(request):
input_dict_4 = {
"r3": {
"route_maps": {
- "rmap_match_pf_1": [{"action": "permit", "set": {"metric": 50,}}]
+ "rmap_match_pf_1": [
+ {
+ "action": "permit",
+ "set": {
+ "metric": 50,
+ },
+ }
+ ]
}
}
}
@@ -1210,7 +1229,13 @@ def test_route_map_match_only_no_set_p0(request):
"r1": {
"route_maps": {
"rmap_match_pf_1_{}".format(addr_type): [
- {"action": "permit", "set": {"metric": 50, "locPrf": 150,}}
+ {
+ "action": "permit",
+ "set": {
+ "metric": 50,
+ "locPrf": 150,
+ },
+ }
]
}
}
diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py
index 3056aa29f3..958eceba62 100644
--- a/tests/topotests/bgp-route-map/test_route_map_topo2.py
+++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py
@@ -268,12 +268,20 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0():
"prefix_lists": {
"ipv4": {
"pf_list_1_ipv4": [
- {"seqid": 10, "network": "any", "action": "permit",}
+ {
+ "seqid": 10,
+ "network": "any",
+ "action": "permit",
+ }
]
},
"ipv6": {
"pf_list_1_ipv6": [
- {"seqid": 10, "network": "any", "action": "permit",}
+ {
+ "seqid": 10,
+ "network": "any",
+ "action": "permit",
+ }
]
},
}
@@ -472,7 +480,11 @@ def test_modify_set_match_clauses_in_rmap_p0():
"prefix_lists": {
"ipv4": {
"pf_list_1_ipv4": [
- {"seqid": 10, "network": "any", "action": "permit",}
+ {
+ "seqid": 10,
+ "network": "any",
+ "action": "permit",
+ }
],
"pf_list_2_ipv4": [
{"seqid": 10, "network": "any", "action": "permit"}
@@ -480,7 +492,11 @@ def test_modify_set_match_clauses_in_rmap_p0():
},
"ipv6": {
"pf_list_1_ipv6": [
- {"seqid": 10, "network": "any", "action": "permit",}
+ {
+ "seqid": 10,
+ "network": "any",
+ "action": "permit",
+ }
],
"pf_list_2_ipv6": [
{"seqid": 10, "network": "any", "action": "permit"}
@@ -506,7 +522,9 @@ def test_modify_set_match_clauses_in_rmap_p0():
"prefix_lists": "pf_list_1_{}".format(addr_type)
}
},
- "set": {"locPrf": 150,},
+ "set": {
+ "locPrf": 150,
+ },
}
],
"rmap_match_pf_2_{}".format(addr_type): [
@@ -666,7 +684,9 @@ def test_modify_set_match_clauses_in_rmap_p0():
"prefix_lists": "pf_list_1_{}".format(addr_type)
}
},
- "set": {"locPrf": 1000,},
+ "set": {
+ "locPrf": 1000,
+ },
}
],
"rmap_match_pf_2_{}".format(addr_type): [
@@ -816,12 +836,20 @@ def test_modify_prefix_list_referenced_by_rmap_p0():
"prefix_lists": {
"ipv4": {
"pf_list_1_ipv4": [
- {"seqid": 10, "network": "any", "action": "permit",}
+ {
+ "seqid": 10,
+ "network": "any",
+ "action": "permit",
+ }
]
},
"ipv6": {
"pf_list_1_ipv6": [
- {"seqid": 100, "network": "any", "action": "permit",}
+ {
+ "seqid": 100,
+ "network": "any",
+ "action": "permit",
+ }
]
},
}
@@ -1090,7 +1118,9 @@ def test_remove_prefix_list_referenced_by_rmap_p0():
"prefix_lists": "pf_list_1_{}".format(addr_type)
}
},
- "set": {"locPrf": 150,},
+ "set": {
+ "locPrf": 150,
+ },
}
],
"rmap_match_pf_2_{}".format(addr_type): [
@@ -1894,7 +1924,9 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1():
"prefix_lists": "pf_list_1_{}".format(addr_type)
}
},
- "set": {"locPrf": 150,},
+ "set": {
+ "locPrf": 150,
+ },
}
]
}
@@ -1921,7 +1953,9 @@ def test_multiple_match_statement_in_route_map_logical_ANDed_p1():
}
}
},
- "set": {"locPrf": 150,},
+ "set": {
+ "locPrf": 150,
+ },
}
]
}
@@ -2048,7 +2082,9 @@ def test_add_remove_rmap_to_specific_neighbor_p0():
"prefix_lists": "pf_list_1_{}".format(addr_type)
}
},
- "set": {"locPrf": 150,},
+ "set": {
+ "locPrf": 150,
+ },
}
]
}
@@ -3505,7 +3541,9 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
"prefix_lists": "pf_list_1_{}".format(addr_type)
}
},
- "set": {"locPrf": 150,},
+ "set": {
+ "locPrf": 150,
+ },
}
],
"rmap_match_pf_2_{}".format(addr_type): [
diff --git a/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py b/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py
index 36f1d8cd56..71f64e9b70 100644
--- a/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py
+++ b/tests/topotests/bgp-vrf-route-leak-basic/test_bgp-vrf-route-leak-basic.py
@@ -90,7 +90,11 @@ def test_vrf_route_leak():
# Test DONNA VRF.
expect = {
- "10.0.0.0/24": [{"protocol": "connected",}],
+ "10.0.0.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
"10.0.1.0/24": [
{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
],
@@ -111,11 +115,19 @@ def test_vrf_route_leak():
"10.0.0.0/24": [
{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
],
- "10.0.1.0/24": [{"protocol": "connected",}],
+ "10.0.1.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
"10.0.2.0/24": [
{"protocol": "bgp", "selected": True, "nexthops": [{"fib": True}]}
],
- "10.0.3.0/24": [{"protocol": "connected",}],
+ "10.0.3.0/24": [
+ {
+ "protocol": "connected",
+ }
+ ],
}
test_func = partial(
diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py
index bc821bd7a0..5f3809c2b3 100644
--- a/tests/topotests/bgp_features/test_bgp_features.py
+++ b/tests/topotests/bgp_features/test_bgp_features.py
@@ -753,41 +753,71 @@ def test_bgp_delayopen_without():
pytest.skip(tgen.errors)
# part 1: no delay r1 <=> no delay r4
- logger.info("Starting optional test of BGP functionality without DelayOpenTimer enabled to establish a reference for following tests")
+ logger.info(
+ "Starting optional test of BGP functionality without DelayOpenTimer enabled to establish a reference for following tests"
+ )
# 1.1 enable peering shutdown
logger.info("Enable shutdown of peering between r1 and r4")
- tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"')
- tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"')
+ tgen.net["r1"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"'
+ )
+ tgen.net["r4"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"'
+ )
# 1.2 wait for peers to shut down (poll output)
for router_num in [1, 4]:
- logger.info("Checking BGP summary after enabling shutdown of peering on r{}".format(router_num))
+ logger.info(
+ "Checking BGP summary after enabling shutdown of peering on r{}".format(
+ router_num
+ )
+ )
router = tgen.gears["r{}".format(router_num)]
- reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num))
+ reffile = os.path.join(
+ CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)
+ )
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
assert res is None, assertmsg
# 1.3 disable peering shutdown
logger.info("Disable shutdown of peering between r1 and r4")
- tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"')
- tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"')
+ tgen.net["r1"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"'
+ )
+ tgen.net["r4"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"'
+ )
# 1.4 wait for peers to establish connection (poll output)
for router_num in [1, 4]:
- logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num))
+ logger.info(
+ "Checking BGP summary after disabling shutdown of peering on r{}".format(
+ router_num
+ )
+ )
router = tgen.gears["r{}".format(router_num)]
- reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num))
+ reffile = os.path.join(
+ CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)
+ )
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
- assertmsg = "BGP session on r{} did not establish a connection with peer".format(router_num)
+ assertmsg = (
+ "BGP session on r{} did not establish a connection with peer".format(
+ router_num
+ )
+ )
assert res is None, assertmsg
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
# end test_bgp_delayopen_without
@@ -800,65 +830,107 @@ def test_bgp_delayopen_singular():
pytest.skip(tgen.errors)
# part 2: delay 240s r1 <=> no delay r4
- logger.info("Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on one side of the peering")
+ logger.info(
+ "Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on one side of the peering"
+ )
# 2.1 enable peering shutdown
logger.info("Enable shutdown of peering between r1 and r4")
- tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"')
- tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"')
+ tgen.net["r1"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 shutdown"'
+ )
+ tgen.net["r4"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65100" -c "neighbor 192.168.101.1 shutdown"'
+ )
# 2.2 wait for peers to shut down (poll output)
for router_num in [1, 4]:
- logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num))
+ logger.info(
+ "Checking BGP summary after disabling shutdown of peering on r{}".format(
+ router_num
+ )
+ )
router = tgen.gears["r{}".format(router_num)]
- reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num))
+ reffile = os.path.join(
+ CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)
+ )
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
assert res is None, assertmsg
# 2.3 set delayopen on R1 to 240
logger.info("Setting DelayOpenTime for neighbor r4 to 240 seconds on r1")
- tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 timers delayopen 240"')
+ tgen.net["r1"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.101.2 timers delayopen 240"'
+ )
# 2.4 check config (poll output)
logger.info("Checking BGP neighbor configuration after setting DelayOpenTime on r1")
router = tgen.gears["r1"]
reffile = os.path.join(CWD, "r1/bgp_delayopen_neighbor.json")
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show bgp neighbors json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show bgp neighbors json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
assertmsg = "BGP session on r1 failed to set DelayOpenTime for r4"
assert res is None, assertmsg
# 2.5 disable peering shutdown
logger.info("Disable shutdown of peering between r1 and r4")
- tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"')
- tgen.net["r4"].cmd('vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"')
+ tgen.net["r1"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 shutdown"'
+ )
+ tgen.net["r4"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65100" -c "no neighbor 192.168.101.1 shutdown"'
+ )
# 2.6 wait for peers to establish connection (poll output)
for router_num in [1, 4]:
- logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num))
+ logger.info(
+ "Checking BGP summary after disabling shutdown of peering on r{}".format(
+ router_num
+ )
+ )
router = tgen.gears["r{}".format(router_num)]
- reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num))
+ reffile = os.path.join(
+ CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)
+ )
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=5, wait=1)
- assertmsg = "BGP session on r{} did not establish a connection with peer".format(router_num)
+ assertmsg = (
+ "BGP session on r{} did not establish a connection with peer".format(
+ router_num
+ )
+ )
assert res is None, assertmsg
# 2.7 unset delayopen on R1
logger.info("Disabling DelayOpenTimer for neighbor r4 on r1")
- tgen.net["r1"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 timers delayopen"')
+ tgen.net["r1"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.101.2 timers delayopen"'
+ )
# 2.8 check config (poll output)
- logger.info("Checking BGP neighbor configuration after disabling DelayOpenTimer on r1")
- delayopen_cfg = tgen.net["r1"].cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"').rstrip()
+ logger.info(
+ "Checking BGP neighbor configuration after disabling DelayOpenTimer on r1"
+ )
+ delayopen_cfg = (
+ tgen.net["r1"]
+ .cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"')
+ .rstrip()
+ )
assertmsg = "BGP session on r1 failed disable DelayOpenTimer for peer r4"
assert delayopen_cfg == "", assertmsg
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
# end test_bgp_delayopen_singular
@@ -870,67 +942,119 @@ def test_bgp_delayopen_dual():
pytest.skip(tgen.errors)
# part 3: delay 60s R2 <=> delay 30s R5
- logger.info("Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on both sides of the peering with different timer intervals")
+ logger.info(
+ "Starting test of BGP functionality and behaviour with DelayOpenTimer enabled on both sides of the peering with different timer intervals"
+ )
# 3.1 enable peering shutdown
logger.info("Enable shutdown of peering between r2 and r5")
- tgen.net["r2"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 shutdown"')
- tgen.net["r5"].cmd('vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 shutdown"')
+ tgen.net["r2"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 shutdown"'
+ )
+ tgen.net["r5"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 shutdown"'
+ )
# 3.2 wait for peers to shut down (pool output)
for router_num in [2, 5]:
- logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num))
+ logger.info(
+ "Checking BGP summary after disabling shutdown of peering on r{}".format(
+ router_num
+ )
+ )
router = tgen.gears["r{}".format(router_num)]
- reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num))
+ reffile = os.path.join(
+ CWD, "r{}/bgp_delayopen_summary_shutdown.json".format(router_num)
+ )
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
assertmsg = "BGP session on r{} did not shut down peer".format(router_num)
assert res is None, assertmsg
# 3.3 set delayopen on R2 to 60s and on R5 to 30s
logger.info("Setting DelayOpenTime for neighbor r5 to 60 seconds on r2")
- tgen.net["r2"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 timers delayopen 60"')
+ tgen.net["r2"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "neighbor 192.168.201.2 timers delayopen 60"'
+ )
logger.info("Setting DelayOpenTime for neighbor r2 to 30 seconds on r5")
- tgen.net["r5"].cmd('vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 timers delayopen 30"')
+ tgen.net["r5"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65200" -c "neighbor 192.168.201.1 timers delayopen 30"'
+ )
# 3.4 check config (poll output)
for router_num in [2, 5]:
- logger.info("Checking BGP neighbor configuration after setting DelayOpenTime on r{}i".format(router_num))
+ logger.info(
+ "Checking BGP neighbor configuration after setting DelayOpenTime on r{}i".format(
+ router_num
+ )
+ )
router = tgen.gears["r{}".format(router_num)]
- reffile = os.path.join(CWD, "r{}/bgp_delayopen_neighbor.json".format(router_num))
+ reffile = os.path.join(
+ CWD, "r{}/bgp_delayopen_neighbor.json".format(router_num)
+ )
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show bgp neighbors json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show bgp neighbors json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
assertmsg = "BGP session on r{} failed to set DelayOpenTime".format(router_num)
assert res is None, assertmsg
## 3.5 disable peering shutdown
logger.info("Disable shutdown of peering between r2 and r5")
- tgen.net["r2"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 shutdown"')
- tgen.net["r5"].cmd('vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 shutdown"')
+ tgen.net["r2"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 shutdown"'
+ )
+ tgen.net["r5"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 shutdown"'
+ )
## 3.6 wait for peers to reach connect or active state (poll output)
delay_start = int(time.time())
for router_num in [2, 5]:
- logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num))
+ logger.info(
+ "Checking BGP summary after disabling shutdown of peering on r{}".format(
+ router_num
+ )
+ )
router = tgen.gears["r{}".format(router_num)]
- reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_connect.json".format(router_num))
+ reffile = os.path.join(
+ CWD, "r{}/bgp_delayopen_summary_connect.json".format(router_num)
+ )
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=3, wait=1)
- assertmsg = "BGP session on r{} did not enter Connect state with peer".format(router_num)
+ assertmsg = "BGP session on r{} did not enter Connect state with peer".format(
+ router_num
+ )
assert res is None, assertmsg
## 3.7 wait for peers to establish connection (poll output)
for router_num in [2, 5]:
- logger.info("Checking BGP summary after disabling shutdown of peering on r{}".format(router_num))
+ logger.info(
+ "Checking BGP summary after disabling shutdown of peering on r{}".format(
+ router_num
+ )
+ )
router = tgen.gears["r{}".format(router_num)]
- reffile = os.path.join(CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num))
+ reffile = os.path.join(
+ CWD, "r{}/bgp_delayopen_summary_established.json".format(router_num)
+ )
expected = json.loads(open(reffile).read())
- test_func = functools.partial(topotest.router_json_cmp, router, "show ip bgp summary json", expected)
+ test_func = functools.partial(
+ topotest.router_json_cmp, router, "show ip bgp summary json", expected
+ )
_, res = topotest.run_and_expect(test_func, None, count=35, wait=1)
- assertmsg = "BGP session on r{} did not establish a connection with peer".format(router_num)
+ assertmsg = (
+ "BGP session on r{} did not establish a connection with peer".format(
+ router_num
+ )
+ )
assert res is None, assertmsg
delay_stop = int(time.time())
@@ -939,18 +1063,32 @@ def test_bgp_delayopen_dual():
# 3.8 unset delayopen on R2 and R5
logger.info("Disabling DelayOpenTimer for neighbor r5 on r2")
- tgen.net["r2"].cmd('vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 timers delayopen"')
+ tgen.net["r2"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65000" -c "no neighbor 192.168.201.2 timers delayopen"'
+ )
logger.info("Disabling DelayOpenTimer for neighbor r2 on r5")
- tgen.net["r5"].cmd('vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 timers delayopen"')
+ tgen.net["r5"].cmd(
+ 'vtysh -c "conf t" -c "router bgp 65200" -c "no neighbor 192.168.201.1 timers delayopen"'
+ )
# 3.9 check config (poll output)
for router_num in [2, 5]:
- logger.info("Checking BGP neighbor configuration after disabling DelayOpenTimer on r{}".format(router_num))
- delayopen_cfg = tgen.net["r{}".format(router_num)].cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"').rstrip()
- assertmsg = "BGP session on r{} failed disable DelayOpenTimer".format(router_num)
+ logger.info(
+ "Checking BGP neighbor configuration after disabling DelayOpenTimer on r{}".format(
+ router_num
+ )
+ )
+ delayopen_cfg = (
+ tgen.net["r{}".format(router_num)]
+ .cmd('vtysh -c "show bgp neighbors json" | grep "DelayOpenTimeMsecs"')
+ .rstrip()
+ )
+ assertmsg = "BGP session on r{} failed disable DelayOpenTimer".format(
+ router_num
+ )
assert delayopen_cfg == "", assertmsg
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
# end test_bgp_delayopen_dual
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
index 097b654e77..94fd17e012 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
@@ -316,7 +316,9 @@ def test_BGP_GR_TC_46_p1(request):
input_dict = {
"r1": {
"bgp": {
- "graceful-restart": {"graceful-restart": True,},
+ "graceful-restart": {
+ "graceful-restart": True,
+ },
"address_family": {
"ipv4": {
"unicast": {
@@ -1184,8 +1186,8 @@ def test_BGP_GR_TC_53_p1(request):
def test_BGP_GR_TC_4_p0(request):
"""
- Test Objective : Verify that the restarting node sets "R" bit while sending the
- BGP open messages after the node restart, only if GR is enabled.
+ Test Objective : Verify that the restarting node sets "R" bit while sending the
+ BGP open messages after the node restart, only if GR is enabled.
"""
tgen = get_topogen()
@@ -1368,9 +1370,9 @@ def test_BGP_GR_TC_4_p0(request):
def test_BGP_GR_TC_5_1_2_p1(request):
"""
- Test Objective : Verify if restarting node resets R bit in BGP open message
- during normal BGP session flaps as well, even when GR restarting mode is enabled.
- Here link flap happen due to interface UP/DOWN.
+ Test Objective : Verify if restarting node resets R bit in BGP open message
+ during normal BGP session flaps as well, even when GR restarting mode is enabled.
+ Here link flap happen due to interface UP/DOWN.
"""
tgen = get_topogen()
@@ -1815,8 +1817,8 @@ def test_BGP_GR_TC_6_1_2_p1(request):
def test_BGP_GR_TC_8_p1(request):
"""
- Test Objective : Verify that restarting nodes set "F" bit while sending
- the BGP open messages after it restarts, only when BGP GR is enabled.
+ Test Objective : Verify that restarting nodes set "F" bit while sending
+ the BGP open messages after it restarts, only when BGP GR is enabled.
"""
tgen = get_topogen()
@@ -1959,8 +1961,8 @@ def test_BGP_GR_TC_8_p1(request):
def test_BGP_GR_TC_17_p1(request):
"""
- Test Objective : Verify that only GR helper routers keep the stale
- route entries, not any GR disabled router.
+ Test Objective : Verify that only GR helper routers keep the stale
+ route entries, not any GR disabled router.
"""
tgen = get_topogen()
@@ -2145,8 +2147,8 @@ def test_BGP_GR_TC_17_p1(request):
def test_BGP_GR_TC_19_p1(request):
"""
- Test Objective : Verify that GR helper routers keeps all the routes received
- from restarting node if both the routers are configured as GR restarting node.
+ Test Objective : Verify that GR helper routers keeps all the routes received
+ from restarting node if both the routers are configured as GR restarting node.
"""
tgen = get_topogen()
@@ -2325,8 +2327,8 @@ def test_BGP_GR_TC_19_p1(request):
def test_BGP_GR_TC_20_p1(request):
"""
- Test Objective : Verify that GR helper routers delete all the routes
- received from a node if both the routers are configured as GR helper node.
+ Test Objective : Verify that GR helper routers delete all the routes
+ received from a node if both the routers are configured as GR helper node.
"""
tgen = get_topogen()
tc_name = request.node.name
@@ -3090,8 +3092,8 @@ def test_BGP_GR_TC_31_2_p1(request):
def test_BGP_GR_TC_9_p1(request):
"""
- Test Objective : Verify that restarting nodes reset "F" bit while sending
- the BGP open messages after it's restarts, when BGP GR is **NOT** enabled.
+ Test Objective : Verify that restarting nodes reset "F" bit while sending
+ the BGP open messages after it's restarts, when BGP GR is **NOT** enabled.
"""
tgen = get_topogen()
@@ -3264,8 +3266,8 @@ def test_BGP_GR_TC_9_p1(request):
def test_BGP_GR_TC_17_p1(request):
"""
- Test Objective : Verify that only GR helper routers keep the stale
- route entries, not any GR disabled router.
+ Test Objective : Verify that only GR helper routers keep the stale
+ route entries, not any GR disabled router.
"""
tgen = get_topogen()
@@ -3467,7 +3469,13 @@ def test_BGP_GR_TC_43_p1(request):
step("Configure R1 and R2 as GR restarting node in global level")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -3560,7 +3568,13 @@ def test_BGP_GR_TC_43_p1(request):
step("Verify on R2 that R1 doesn't advertise any GR capabilities")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-disable": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -3659,7 +3673,13 @@ def test_BGP_GR_TC_43_p1(request):
step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -3779,7 +3799,13 @@ def test_BGP_GR_TC_44_p1(request):
step("Verify on R2 that R1 advertises GR capabilities as a helper node")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-helper": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -3849,7 +3875,13 @@ def test_BGP_GR_TC_44_p1(request):
start_router_daemons(tgen, "r2", ["bgpd"])
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}}
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-disable": True,
+ }
+ }
+ }
}
configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
@@ -3857,7 +3889,13 @@ def test_BGP_GR_TC_44_p1(request):
step("Verify on R2 that R1 doesn't advertise any GR capabilities")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart-disable": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-disable": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -3941,7 +3979,13 @@ def test_BGP_GR_TC_44_p1(request):
step("Verify on R2 that R1 advertises GR capabilities as a helper node")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-helper": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -4108,14 +4152,28 @@ def test_BGP_GR_TC_45_p1(request):
start_router_daemons(tgen, "r1", ["bgpd"])
- input_dict = {"r1": {"bgp": {"graceful-restart": {"graceful-restart": False,}}}}
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": False,
+ }
+ }
+ }
+ }
configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
step("Verify on R2 that R1 advertises GR capabilities as a helper node")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-helper": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -4199,14 +4257,28 @@ def test_BGP_GR_TC_45_p1(request):
start_router_daemons(tgen, "r2", ["bgpd"])
- input_dict = {"r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}}}
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ }
+ }
+ }
+ }
configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -4307,7 +4379,9 @@ def test_BGP_GR_TC_46_p1(request):
input_dict = {
"r1": {
"bgp": {
- "graceful-restart": {"graceful-restart": True,},
+ "graceful-restart": {
+ "graceful-restart": True,
+ },
"address_family": {
"ipv4": {
"unicast": {
@@ -4559,7 +4633,9 @@ def test_BGP_GR_TC_47_p1(request):
input_dict = {
"r1": {
"bgp": {
- "graceful-restart": {"graceful-restart": True,},
+ "graceful-restart": {
+ "graceful-restart": True,
+ },
"address_family": {
"ipv4": {
"unicast": {
@@ -4698,7 +4774,13 @@ def test_BGP_GR_TC_47_p1(request):
step("Verify on R2 that R1 still advertises GR capabilities as a restarting node")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
}
@@ -4814,7 +4896,9 @@ def test_BGP_GR_TC_48_p1(request):
input_dict = {
"r1": {
"bgp": {
- "graceful-restart": {"graceful-restart": True,},
+ "graceful-restart": {
+ "graceful-restart": True,
+ },
"address_family": {
"ipv4": {
"unicast": {
@@ -4960,7 +5044,13 @@ def test_BGP_GR_TC_48_p1(request):
step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
input_dict = {
- "r1": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ }
+ }
+ },
"r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}},
}
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
index 6926121a6b..2ddeab13f6 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
@@ -456,7 +456,9 @@ def test_BGP_GR_TC_3_p0(request):
input_dict = {
"r1": {
"bgp": {
- "graceful-restart": {"disable-eor": True,},
+ "graceful-restart": {
+ "disable-eor": True,
+ },
"address_family": {
"ipv4": {
"unicast": {
@@ -2095,7 +2097,10 @@ def test_BGP_GR_chaos_33_p1(request):
"ipv4": {
"unicast": {
"advertise_networks": [
- {"network": "200.0.20.1/32", "no_of_network": 2,}
+ {
+ "network": "200.0.20.1/32",
+ "no_of_network": 2,
+ }
]
}
},
@@ -2207,13 +2212,13 @@ def test_BGP_GR_chaos_33_p1(request):
else:
next_hop_6 = NEXT_HOP_6[1]
- result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6,
- expected=False)
- assert result is not True,\
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
- logger.info(" Expected behavior: {}".\
- format(result))
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_2, next_hop_6, expected=False
+ )
+ assert result is not True, "Testcase {} :Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
logger.info("[Step 4] : Start BGPd daemon on R1 and R4..")
@@ -3960,7 +3965,13 @@ def test_BGP_GR_21_p2(request):
}
}
},
- "r2": {"bgp": {"graceful-restart": {"graceful-restart": True,}}},
+ "r2": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ }
+ }
+ },
}
configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
index 9c0355a3e9..c2858a4bd0 100644
--- a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
+++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py
@@ -2132,7 +2132,11 @@ def test_large_community_lists_with_rmap_match_regex(request):
{
"action": "permit",
"seq_id": "10",
- "match": {"large_community_list": {"id": "ALL",},},
+ "match": {
+ "large_community_list": {
+ "id": "ALL",
+ },
+ },
}
]
}
@@ -2208,7 +2212,11 @@ def test_large_community_lists_with_rmap_match_regex(request):
{
"action": "permit",
"seq_id": "20",
- "match": {"large_community_list": {"id": "EXP_ALL",},},
+ "match": {
+ "large_community_list": {
+ "id": "EXP_ALL",
+ },
+ },
}
]
}
diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
index 9703cf8d57..d34446e2ee 100644
--- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
+++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
@@ -95,7 +95,7 @@ from lib.common_config import (
kill_router_daemons,
start_router_daemons,
stop_router,
- start_router
+ start_router,
)
from lib.topolog import logger
@@ -129,7 +129,7 @@ LOOPBACK_2 = {
"ipv4": "20.20.20.20/32",
"ipv6": "20::20:20/128",
"ipv4_mask": "255.255.255.255",
- "ipv6_mask": None
+ "ipv6_mask": None,
}
MAX_PATHS = 2
@@ -724,16 +724,40 @@ def test_vrf_with_multiple_links_p1(request):
"local_as": "200",
"vrf": "RED_A",
"address_family": {
- "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
- "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ "ipv4": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": MAX_PATHS,
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": MAX_PATHS,
+ }
+ }
+ },
},
},
{
"local_as": "200",
"vrf": "BLUE_A",
"address_family": {
- "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
- "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ "ipv4": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": MAX_PATHS,
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": MAX_PATHS,
+ }
+ }
+ },
},
},
]
@@ -2148,7 +2172,7 @@ def test_restart_bgpd_daemon_p1(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
result = verify_bgp_convergence(tgen, topo)
- assert result is True, "Testcase () :Failed\n Error {}". format(tc_name, result)
+ assert result is True, "Testcase () :Failed\n Error {}".format(tc_name, result)
step("Kill BGPd daemon on R1.")
kill_router_daemons(tgen, "r1", ["bgpd"])
diff --git a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
index 6d7131e1e5..ceac84709b 100644
--- a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
+++ b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py
@@ -101,7 +101,11 @@ def test_r1_receive_and_advertise_prefix_sid_type1():
"prefix": prefix,
"advertisedTo": {"10.0.0.101": {}, "10.0.0.102": {}},
"paths": [
- {"valid": True, "remoteLabel": remoteLabel, "labelIndex": labelIndex,}
+ {
+ "valid": True,
+ "remoteLabel": remoteLabel,
+ "labelIndex": labelIndex,
+ }
],
}
return topotest.json_cmp(output, expected)
diff --git a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py
index 3af944473d..3f9009967d 100644
--- a/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py
+++ b/tests/topotests/bgp_recursive_route_ebgp_multi_hop/test_bgp_recursive_route_ebgp_multi_hop.py
@@ -1042,9 +1042,10 @@ def test_next_hop_with_recursive_lookup_p1(request):
next_hop=next_hop,
expected=False,
)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "Route is still present \n Error : {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format(
+ tc_name, result
)
step("Re-apply redistribution on R4.")
@@ -1125,9 +1126,10 @@ def test_next_hop_with_recursive_lookup_p1(request):
next_hop=next_hop,
expected=False,
)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "Route is still present \n Error : {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format(
+ tc_name, result
)
shutdown_bringup_interface(tgen, "r3", intf_r3_r4, True)
@@ -1182,9 +1184,10 @@ def test_next_hop_with_recursive_lookup_p1(request):
next_hop=next_hop,
expected=False,
)
- assert result is not True, (
- "Testcase {} : Failed \n "
- "Route is still present \n Error : {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n " "Route is still present \n Error : {}".format(
+ tc_name, result
)
shutdown_bringup_interface(tgen, "r4", intf_r4_r3, True)
@@ -2101,8 +2104,20 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request):
"r4": {
"bgp": {
"address_family": {
- "ipv4": {"unicast": {"maximum_paths": {"ebgp": 1,}}},
- "ipv6": {"unicast": {"maximum_paths": {"ebgp": 1,}}},
+ "ipv4": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": 1,
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": 1,
+ }
+ }
+ },
}
}
}
@@ -2131,8 +2146,20 @@ def test_BGP_active_standby_preemption_and_ecmp_p1(request):
"r4": {
"bgp": {
"address_family": {
- "ipv4": {"unicast": {"maximum_paths": {"ebgp": 2,}}},
- "ipv6": {"unicast": {"maximum_paths": {"ebgp": 2,}}},
+ "ipv4": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": 2,
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "maximum_paths": {
+ "ebgp": 2,
+ }
+ }
+ },
}
}
}
diff --git a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
index 0fabd90341..0467bf1bfb 100644
--- a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
+++ b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py
@@ -415,9 +415,10 @@ def test_route_summarisation_with_summary_only_p1(request):
result = verify_rib(
tgen, addr_type, "r3", input_static, protocol="bgp", expected=False
)
- assert result is not True, (
- "Testcase : Failed \n "
- "Routes are still present \n Error: {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase : Failed \n " "Routes are still present \n Error: {}".format(
+ tc_name, result
)
result = verify_rib(tgen, addr_type, "r1", input_static_agg, protocol="bgp")
@@ -614,7 +615,9 @@ def test_route_summarisation_with_summary_only_p1(request):
addr_type: {
"unicast": {
"advertise_networks": [
- {"network": NETWORK_4_1[addr_type],}
+ {
+ "network": NETWORK_4_1[addr_type],
+ }
]
}
}
@@ -1014,7 +1017,11 @@ def test_route_summarisation_with_as_set_p1(request):
assert result is True, "Testcase : Failed \n Error: {}".format(tc_name, result)
for addr_type in ADDR_TYPES:
- for pfx, seq_id, network, in zip([6, 7], [60, 70], [NETWORK_3_1, NETWORK_4_1]):
+ for (
+ pfx,
+ seq_id,
+ network,
+ ) in zip([6, 7], [60, 70], [NETWORK_3_1, NETWORK_4_1]):
prefix_list = {
"r1": {
"prefix_lists": {
diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
index cf8be5f44f..c75055c26f 100644
--- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
+++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
@@ -56,6 +56,7 @@ class TemplateTopo(Topo):
switch.add_link(tgen.gears["r2"])
switch.add_link(tgen.gears["r3"])
+
def setup_module(mod):
tgen = Topogen(TemplateTopo, mod.__name__)
tgen.start_topology()
@@ -114,6 +115,7 @@ def test_bgp_route():
assertmsg = '"r3" JSON output mismatches'
assert result is None, assertmsg
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
index 9106c163cd..6e7495d929 100644
--- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
@@ -943,9 +943,10 @@ def test_modify_route_map_match_set_clauses_p1(request):
}
result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1, expected=False)
- assert result is not True, (
- "Testcase {} : Failed \n Error : Routes are still "
- "present {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Error : Routes are still " "present {}".format(
+ tc_name, result
)
write_test_footer(tc_name)
diff --git a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py
index 67edcae90e..6f80ffd1aa 100755
--- a/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py
+++ b/tests/topotests/isis-lfa-topo1/test_isis_lfa_topo1.py
@@ -62,7 +62,7 @@ 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, '../'))
+sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
# Import topogen and topotest helpers
@@ -76,8 +76,10 @@ from mininet.topo import Topo
# 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)
@@ -85,59 +87,58 @@ class TemplateTopo(Topo):
#
# Define FRR Routers
#
- for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']:
+ 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['rt2'], nodeif="eth-rt3")
- switch.add_link(tgen.gears['rt3'], nodeif="eth-rt2")
- switch = tgen.add_switch('s3')
- switch.add_link(tgen.gears['rt1'], nodeif="eth-rt3")
- switch.add_link(tgen.gears['rt3'], nodeif="eth-rt1")
- switch = tgen.add_switch('s4')
- switch.add_link(tgen.gears['rt1'], nodeif="eth-rt4")
- switch.add_link(tgen.gears['rt4'], nodeif="eth-rt1")
- switch = tgen.add_switch('s5')
- switch.add_link(tgen.gears['rt1'], nodeif="eth-rt5")
- switch.add_link(tgen.gears['rt5'], nodeif="eth-rt1")
- switch = tgen.add_switch('s6')
- switch.add_link(tgen.gears['rt1'], nodeif="eth-rt6")
- switch.add_link(tgen.gears['rt6'], nodeif="eth-rt1")
- switch = tgen.add_switch('s7')
- switch.add_link(tgen.gears['rt2'], nodeif="eth-rt7")
- switch.add_link(tgen.gears['rt7'], nodeif="eth-rt2")
- switch = tgen.add_switch('s8')
- switch.add_link(tgen.gears['rt3'], nodeif="eth-rt7")
- switch.add_link(tgen.gears['rt7'], nodeif="eth-rt3")
- switch = tgen.add_switch('s9')
- switch.add_link(tgen.gears['rt4'], nodeif="eth-rt7")
- switch.add_link(tgen.gears['rt7'], nodeif="eth-rt4")
- switch = tgen.add_switch('s10')
- switch.add_link(tgen.gears['rt5'], nodeif="eth-rt7")
- switch.add_link(tgen.gears['rt7'], nodeif="eth-rt5")
- switch = tgen.add_switch('s11')
- switch.add_link(tgen.gears['rt6'], nodeif="eth-rt7")
- switch.add_link(tgen.gears['rt7'], nodeif="eth-rt6")
+ 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["rt2"], nodeif="eth-rt3")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt2")
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt3")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt1")
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt4")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt1")
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt5")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt1")
+ switch = tgen.add_switch("s6")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-rt6")
+ switch.add_link(tgen.gears["rt6"], nodeif="eth-rt1")
+ switch = tgen.add_switch("s7")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt7")
+ switch.add_link(tgen.gears["rt7"], nodeif="eth-rt2")
+ switch = tgen.add_switch("s8")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt7")
+ switch.add_link(tgen.gears["rt7"], nodeif="eth-rt3")
+ switch = tgen.add_switch("s9")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt7")
+ switch.add_link(tgen.gears["rt7"], nodeif="eth-rt4")
+ switch = tgen.add_switch("s10")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt7")
+ switch.add_link(tgen.gears["rt7"], nodeif="eth-rt5")
+ switch = tgen.add_switch("s11")
+ switch.add_link(tgen.gears["rt6"], nodeif="eth-rt7")
+ switch.add_link(tgen.gears["rt7"], nodeif="eth-rt6")
#
# Populate multi-dimensional dictionary containing all expected outputs
#
- files = ["show_ipv6_route.ref",
- "show_yang_interface_isis_adjacencies.ref"]
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']:
+ files = ["show_ipv6_route.ref", "show_yang_interface_isis_adjacencies.ref"]
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
outputs[rname] = {}
for step in range(1, 13 + 1):
outputs[rname][step] = {}
for file in files:
if step == 1:
# Get snapshots relative to the expected initial network convergence
- filename = '{}/{}/step{}/{}'.format(CWD, rname, step, file)
+ filename = "{}/{}/step{}/{}".format(CWD, rname, step, file)
outputs[rname][step][file] = open(filename).read()
else:
if rname != "rt1":
@@ -146,20 +147,23 @@ class TemplateTopo(Topo):
continue
# Get diff relative to the previous step
- filename = '{}/{}/step{}/{}.diff'.format(CWD, rname, step, file)
+ filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file)
# Create temporary files in order to apply the diff
f_in = tempfile.NamedTemporaryFile()
f_in.write(outputs[rname][step - 1][file])
f_in.flush()
f_out = tempfile.NamedTemporaryFile()
- os.system("patch -s -o %s %s %s" %(f_out.name, f_in.name, filename))
+ os.system(
+ "patch -s -o %s %s %s" % (f_out.name, f_in.name, filename)
+ )
# Store the updated snapshot and remove the temporary files
outputs[rname][step][file] = open(f_out.name).read()
f_in.close()
f_out.close()
+
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
@@ -170,16 +174,15 @@ def setup_module(mod):
# For all registered routers, load the zebra configuration file
for rname, router in router_list.iteritems():
router.load_config(
- TopoRouter.RD_ZEBRA,
- os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
- TopoRouter.RD_ISIS,
- os.path.join(CWD, '{}/isisd.conf'.format(rname))
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
)
tgen.start_router()
+
def teardown_module(mod):
"Teardown the pytest environment"
tgen = get_topogen()
@@ -187,6 +190,7 @@ def teardown_module(mod):
# This function tears down the whole topology.
tgen.stop_topology()
+
def router_compare_json_output(rname, command, reference):
"Compare router JSON output"
@@ -196,12 +200,12 @@ def router_compare_json_output(rname, command, reference):
expected = json.loads(reference)
# Run test function until we get an result. Wait at most 60 seconds.
- test_func = partial(topotest.router_json_cmp,
- tgen.gears[rname], command, expected)
+ test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
_, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
assert diff is None, assertmsg
+
#
# Step 1
#
@@ -215,9 +219,13 @@ def test_isis_adjacencies_step1():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']:
- router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
- outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+ router_compare_json_output(
+ rname,
+ "show yang operational-data /frr-interface:lib isisd",
+ outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"],
+ )
+
def test_rib_ipv6_step1():
logger.info("Test (step 1): verify IPv6 RIB")
@@ -227,9 +235,11 @@ def test_rib_ipv6_step1():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6', 'rt7']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][1]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"]
+ )
+
#
# Step 2
@@ -248,16 +258,28 @@ def test_rib_ipv6_step2():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Disabling LFA protection on all rt1 interfaces')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute lfa"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "no isis fast-reroute lfa"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "no isis fast-reroute lfa"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt6" -c "no isis fast-reroute lfa"')
+ logger.info("Disabling LFA protection on all rt1 interfaces")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt3" -c "no isis fast-reroute lfa"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt4" -c "no isis fast-reroute lfa"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt5" -c "no isis fast-reroute lfa"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt6" -c "no isis fast-reroute lfa"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"]
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][2]["show_ipv6_route.ref"])
#
# Step 3
@@ -276,16 +298,28 @@ def test_rib_ipv6_step3():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Re-enabling LFA protection on all rt1 interfaces')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute lfa"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "isis fast-reroute lfa"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "isis fast-reroute lfa"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt6" -c "isis fast-reroute lfa"')
+ logger.info("Re-enabling LFA protection on all rt1 interfaces")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt3" -c "isis fast-reroute lfa"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt4" -c "isis fast-reroute lfa"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt5" -c "isis fast-reroute lfa"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt6" -c "isis fast-reroute lfa"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"]
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][3]["show_ipv6_route.ref"])
#
# Step 4
@@ -304,12 +338,16 @@ def test_rib_ipv6_step4():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Disabling LFA load-sharing on rt1')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute load-sharing disable"')
+ logger.info("Disabling LFA load-sharing on rt1")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute load-sharing disable"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"]
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][4]["show_ipv6_route.ref"])
#
# Step 5
@@ -328,12 +366,16 @@ def test_rib_ipv6_step5():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Re-enabling LFA load-sharing on rt1')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute load-sharing disable"')
+ logger.info("Re-enabling LFA load-sharing on rt1")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute load-sharing disable"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"]
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][5]["show_ipv6_route.ref"])
#
# Step 6
@@ -352,12 +394,16 @@ def test_rib_ipv6_step6():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Limiting backup computation to critical priority prefixes only')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute priority-limit critical"')
+ logger.info("Limiting backup computation to critical priority prefixes only")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute priority-limit critical"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"]
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][6]["show_ipv6_route.ref"])
#
# Step 7
@@ -377,13 +423,19 @@ def test_rib_ipv6_step7():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Configuring a prefix priority list')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "spf prefix-priority critical CRITICAL_DESTINATIONS"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"')
+ logger.info("Configuring a prefix priority list")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "spf prefix-priority critical CRITICAL_DESTINATIONS"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"]
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][7]["show_ipv6_route.ref"])
#
# Step 8
@@ -402,14 +454,22 @@ def test_rib_ipv6_step8():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Reverting previous changes related to prefix priorities')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "no ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute priority-limit critical"')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf prefix-priority critical CRITICAL_DESTINATIONS"')
+ logger.info("Reverting previous changes related to prefix priorities")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "no ipv6 access-list CRITICAL_DESTINATIONS seq 5 permit 2001:db8:1000::7/128"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "no fast-reroute priority-limit critical"'
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "no spf prefix-priority critical CRITICAL_DESTINATIONS"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"]
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][8]["show_ipv6_route.ref"])
#
# Step 9
@@ -428,12 +488,16 @@ def test_rib_ipv6_step9():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Excluding eth-rt6 from LFA computation for eth-rt2\'s failure')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa exclude interface eth-rt6"')
+ logger.info("Excluding eth-rt6 from LFA computation for eth-rt2's failure")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt2" -c "isis fast-reroute lfa exclude interface eth-rt6"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"]
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][9]["show_ipv6_route.ref"])
#
# Step 10
@@ -452,12 +516,20 @@ def test_rib_ipv6_step10():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Removing exclusion of eth-rt6 from LFA computation for eth-rt2\'s failure')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa exclude interface eth-rt6"')
+ logger.info(
+ "Removing exclusion of eth-rt6 from LFA computation for eth-rt2's failure"
+ )
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-rt2" -c "no isis fast-reroute lfa exclude interface eth-rt6"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][10]["show_ipv6_route.ref"],
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][10]["show_ipv6_route.ref"])
#
# Step 11
@@ -476,12 +548,18 @@ def test_rib_ipv6_step11():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Adding LFA tiebreaker: prefer node protecting backup path')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker node-protecting index 10"')
+ logger.info("Adding LFA tiebreaker: prefer node protecting backup path")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker node-protecting index 10"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][11]["show_ipv6_route.ref"],
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][11]["show_ipv6_route.ref"])
#
# Step 12
@@ -500,12 +578,18 @@ def test_rib_ipv6_step12():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Adding LFA tiebreaker: prefer backup path via downstream node')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker downstream index 20"')
+ logger.info("Adding LFA tiebreaker: prefer backup path via downstream node")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker downstream index 20"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][12]["show_ipv6_route.ref"],
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][12]["show_ipv6_route.ref"])
#
# Step 13
@@ -524,22 +608,29 @@ def test_rib_ipv6_step13():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Adding LFA tiebreaker: prefer backup path with lowest total metric')
- tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker lowest-backup-metric index 30"')
+ logger.info("Adding LFA tiebreaker: prefer backup path with lowest total metric")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "fast-reroute lfa tiebreaker lowest-backup-metric index 30"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][13]["show_ipv6_route.ref"],
+ )
- for rname in ['rt1']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][13]["show_ipv6_route.ref"])
# 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')
+ pytest.skip("Memory leak test/report is disabled")
tgen.report_memory_leaks()
-if __name__ == '__main__':
+
+if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py
index 514ea53552..a1263de8ad 100755
--- a/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py
+++ b/tests/topotests/isis-tilfa-topo1/test_isis_tilfa_topo1.py
@@ -74,7 +74,7 @@ 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, '../'))
+sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
# Import topogen and topotest helpers
@@ -88,8 +88,10 @@ from mininet.topo import Topo
# 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)
@@ -97,80 +99,85 @@ class TemplateTopo(Topo):
#
# Define FRR Routers
#
- for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ for router in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
tgen.add_router(router)
#
# Define connections
#
- switch = tgen.add_switch('s1')
- switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1")
- switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1")
- switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1")
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["rt1"], nodeif="eth-sw1")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-sw1")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-sw1")
- switch = tgen.add_switch('s2')
- switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-1")
- switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-1")
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-1")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-1")
- switch = tgen.add_switch('s3')
- switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-2")
- switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-2")
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["rt2"], nodeif="eth-rt4-2")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt2-2")
- switch = tgen.add_switch('s4')
- switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-1")
- switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-1")
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-1")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-1")
- switch = tgen.add_switch('s5')
- switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-2")
- switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-2")
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["rt3"], nodeif="eth-rt5-2")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt3-2")
- 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("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['rt4'], nodeif="eth-rt6")
- switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4")
+ switch = tgen.add_switch("s7")
+ switch.add_link(tgen.gears["rt4"], nodeif="eth-rt6")
+ switch.add_link(tgen.gears["rt6"], nodeif="eth-rt4")
- switch = tgen.add_switch('s8')
- switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6")
- switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5")
+ switch = tgen.add_switch("s8")
+ switch.add_link(tgen.gears["rt5"], nodeif="eth-rt6")
+ switch.add_link(tgen.gears["rt6"], nodeif="eth-rt5")
#
# Populate multi-dimensional dictionary containing all expected outputs
#
- files = ["show_ip_route.ref",
- "show_ipv6_route.ref",
- "show_mpls_table.ref",
- "show_yang_interface_isis_adjacencies.ref"]
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ files = [
+ "show_ip_route.ref",
+ "show_ipv6_route.ref",
+ "show_mpls_table.ref",
+ "show_yang_interface_isis_adjacencies.ref",
+ ]
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
outputs[rname] = {}
for step in range(1, 9 + 1):
outputs[rname][step] = {}
for file in files:
if step == 1:
# Get snapshots relative to the expected initial network convergence
- filename = '{}/{}/step{}/{}'.format(CWD, rname, step, file)
+ filename = "{}/{}/step{}/{}".format(CWD, rname, step, file)
outputs[rname][step][file] = open(filename).read()
else:
if file == "show_yang_interface_isis_adjacencies.ref":
continue
# Get diff relative to the previous step
- filename = '{}/{}/step{}/{}.diff'.format(CWD, rname, step, file)
+ filename = "{}/{}/step{}/{}.diff".format(CWD, rname, step, file)
# Create temporary files in order to apply the diff
f_in = tempfile.NamedTemporaryFile()
f_in.write(outputs[rname][step - 1][file])
f_in.flush()
f_out = tempfile.NamedTemporaryFile()
- os.system("patch -s -o %s %s %s" %(f_out.name, f_in.name, filename))
+ os.system(
+ "patch -s -o %s %s %s" % (f_out.name, f_in.name, filename)
+ )
# Store the updated snapshot and remove the temporary files
outputs[rname][step][file] = open(f_out.name).read()
f_in.close()
f_out.close()
+
def setup_module(mod):
"Sets up the pytest environment"
tgen = Topogen(TemplateTopo, mod.__name__)
@@ -181,16 +188,15 @@ def setup_module(mod):
# 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))
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
- TopoRouter.RD_ISIS,
- os.path.join(CWD, '{}/isisd.conf'.format(rname))
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
)
tgen.start_router()
+
def teardown_module(mod):
"Teardown the pytest environment"
tgen = get_topogen()
@@ -198,6 +204,7 @@ def teardown_module(mod):
# This function tears down the whole topology.
tgen.stop_topology()
+
def router_compare_json_output(rname, command, reference):
"Compare router JSON output"
@@ -207,12 +214,12 @@ def router_compare_json_output(rname, command, reference):
expected = json.loads(reference)
# Run test function until we get an result. Wait at most 60 seconds.
- test_func = partial(topotest.router_json_cmp,
- tgen.gears[rname], command, expected)
+ test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
_, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
assert diff is None, assertmsg
+
#
# Step 1
#
@@ -226,9 +233,13 @@ def test_isis_adjacencies_step1():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
- outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show yang operational-data /frr-interface:lib isisd",
+ outputs[rname][1]["show_yang_interface_isis_adjacencies.ref"],
+ )
+
def test_rib_ipv4_step1():
logger.info("Test (step 1): verify IPv4 RIB")
@@ -238,9 +249,11 @@ def test_rib_ipv4_step1():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][1]["show_ip_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][1]["show_ip_route.ref"]
+ )
+
def test_rib_ipv6_step1():
logger.info("Test (step 1): verify IPv6 RIB")
@@ -250,9 +263,11 @@ def test_rib_ipv6_step1():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][1]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][1]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step1():
logger.info("Test (step 1): verify MPLS LIB")
@@ -262,9 +277,11 @@ def test_mpls_lib_step1():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][1]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][1]["show_mpls_table.ref"]
+ )
+
#
# Step 2
@@ -283,12 +300,16 @@ def test_rib_ipv4_step2():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Disabling TI-LFA link protection on rt2\'s eth-sw1 interface')
- tgen.net['rt2'].cmd('vtysh -c "conf t" -c "interface eth-sw1" -c "no isis fast-reroute ti-lfa"')
+ logger.info("Disabling TI-LFA link protection on rt2's eth-sw1 interface")
+ tgen.net["rt2"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-sw1" -c "no isis fast-reroute ti-lfa"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][2]["show_ip_route.ref"]
+ )
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][2]["show_ip_route.ref"])
def test_rib_ipv6_step2():
logger.info("Test (step 2): verify IPv6 RIB")
@@ -298,9 +319,11 @@ def test_rib_ipv6_step2():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][2]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][2]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step2():
logger.info("Test (step 2): verify MPLS LIB")
@@ -310,9 +333,11 @@ def test_mpls_lib_step2():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][2]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][2]["show_mpls_table.ref"]
+ )
+
#
# Step 3
@@ -331,12 +356,16 @@ def test_rib_ipv4_step3():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Enabling TI-LFA link protection on rt2\'s eth-sw1 interface')
- tgen.net['rt2'].cmd('vtysh -c "conf t" -c "interface eth-sw1" -c "isis fast-reroute ti-lfa"')
+ logger.info("Enabling TI-LFA link protection on rt2's eth-sw1 interface")
+ tgen.net["rt2"].cmd(
+ 'vtysh -c "conf t" -c "interface eth-sw1" -c "isis fast-reroute ti-lfa"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][3]["show_ip_route.ref"]
+ )
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][3]["show_ip_route.ref"])
def test_rib_ipv6_step3():
logger.info("Test (step 3): verify IPv6 RIB")
@@ -346,9 +375,11 @@ def test_rib_ipv6_step3():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][3]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][3]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step3():
logger.info("Test (step 3): verify MPLS LIB")
@@ -358,9 +389,11 @@ def test_mpls_lib_step3():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][3]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][3]["show_mpls_table.ref"]
+ )
+
#
# Step 4
@@ -384,12 +417,16 @@ def test_rib_ipv4_step4():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Disabling SR on rt4')
- tgen.net['rt4'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing on"')
+ logger.info("Disabling SR on rt4")
+ tgen.net["rt4"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing on"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][4]["show_ip_route.ref"]
+ )
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][4]["show_ip_route.ref"])
def test_rib_ipv6_step4():
logger.info("Test (step 4): verify IPv6 RIB")
@@ -399,9 +436,11 @@ def test_rib_ipv6_step4():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][4]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][4]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step4():
logger.info("Test (step 4): verify MPLS LIB")
@@ -411,9 +450,11 @@ def test_mpls_lib_step4():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][4]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][4]["show_mpls_table.ref"]
+ )
+
#
# Step 5
@@ -432,12 +473,14 @@ def test_rib_ipv4_step5():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Enabling SR on rt4')
- tgen.net['rt4'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing on"')
+ logger.info("Enabling SR on rt4")
+ tgen.net["rt4"].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing on"')
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][5]["show_ip_route.ref"]
+ )
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][5]["show_ip_route.ref"])
def test_rib_ipv6_step5():
logger.info("Test (step 5): verify IPv6 RIB")
@@ -447,9 +490,11 @@ def test_rib_ipv6_step5():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][5]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][5]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step5():
logger.info("Test (step 5): verify MPLS LIB")
@@ -459,9 +504,11 @@ def test_mpls_lib_step5():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][5]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][5]["show_mpls_table.ref"]
+ )
+
#
# Step 6
@@ -480,12 +527,16 @@ def test_rib_ipv4_step6():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Changing rt5\'s SRGB')
- tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 30000 37999"')
+ logger.info("Changing rt5's SRGB")
+ tgen.net["rt5"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 30000 37999"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][6]["show_ip_route.ref"]
+ )
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][6]["show_ip_route.ref"])
def test_rib_ipv6_step6():
logger.info("Test (step 6): verify IPv6 RIB")
@@ -495,9 +546,11 @@ def test_rib_ipv6_step6():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][6]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][6]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step6():
logger.info("Test (step 6): verify MPLS LIB")
@@ -507,9 +560,11 @@ def test_mpls_lib_step6():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][6]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][6]["show_mpls_table.ref"]
+ )
+
#
# Step 7
@@ -529,13 +584,19 @@ def test_rib_ipv4_step7():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Deleting rt5\'s Prefix-SIDs')
- tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 5.5.5.5/32 index 50"')
- tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 2001:db8:1000::5/128 index 51"')
+ logger.info("Deleting rt5's Prefix-SIDs")
+ tgen.net["rt5"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 5.5.5.5/32 index 50"'
+ )
+ tgen.net["rt5"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 2001:db8:1000::5/128 index 51"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][7]["show_ip_route.ref"]
+ )
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][7]["show_ip_route.ref"])
def test_rib_ipv6_step7():
logger.info("Test (step 7): verify IPv6 RIB")
@@ -545,9 +606,11 @@ def test_rib_ipv6_step7():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][7]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][7]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step7():
logger.info("Test (step 7): verify MPLS LIB")
@@ -557,9 +620,11 @@ def test_mpls_lib_step7():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][7]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][7]["show_mpls_table.ref"]
+ )
+
#
# Step 8
@@ -578,13 +643,19 @@ def test_rib_ipv4_step8():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Re-adding rt5\'s Prefix-SIDs')
- tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 50"')
- tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 51"')
+ logger.info("Re-adding rt5's Prefix-SIDs")
+ tgen.net["rt5"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 50"'
+ )
+ tgen.net["rt5"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 51"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][8]["show_ip_route.ref"]
+ )
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][8]["show_ip_route.ref"])
def test_rib_ipv6_step8():
logger.info("Test (step 8): verify IPv6 RIB")
@@ -594,9 +665,11 @@ def test_rib_ipv6_step8():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][8]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][8]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step8():
logger.info("Test (step 8): verify MPLS LIB")
@@ -606,9 +679,11 @@ def test_mpls_lib_step8():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][8]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][8]["show_mpls_table.ref"]
+ )
+
#
# Step 9
@@ -628,13 +703,19 @@ def test_rib_ipv4_step9():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- logger.info('Re-adding rt5\'s Prefix-SIDs')
- tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 500"')
- tgen.net['rt5'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 501"')
+ logger.info("Re-adding rt5's Prefix-SIDs")
+ tgen.net["rt5"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 5.5.5.5/32 index 500"'
+ )
+ tgen.net["rt5"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::5/128 index 501"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][9]["show_ip_route.ref"]
+ )
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ip route isis json",
- outputs[rname][9]["show_ip_route.ref"])
def test_rib_ipv6_step9():
logger.info("Test (step 9): verify IPv6 RIB")
@@ -644,9 +725,11 @@ def test_rib_ipv6_step9():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show ipv6 route isis json",
- outputs[rname][9]["show_ipv6_route.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ipv6 route isis json", outputs[rname][9]["show_ipv6_route.ref"]
+ )
+
def test_mpls_lib_step9():
logger.info("Test (step 9): verify MPLS LIB")
@@ -656,19 +739,22 @@ def test_mpls_lib_step9():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
- router_compare_json_output(rname, "show mpls table json",
- outputs[rname][9]["show_mpls_table.ref"])
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][9]["show_mpls_table.ref"]
+ )
+
# 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')
+ pytest.skip("Memory leak test/report is disabled")
tgen.report_memory_leaks()
-if __name__ == '__main__':
+
+if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/ldp-topo1/test_ldp_topo1.py b/tests/topotests/ldp-topo1/test_ldp_topo1.py
index 31adeafbf6..9822686dfc 100644
--- a/tests/topotests/ldp-topo1/test_ldp_topo1.py
+++ b/tests/topotests/ldp-topo1/test_ldp_topo1.py
@@ -647,9 +647,11 @@ def test_zebra_ipv4_routingTable():
else:
print("r%s ok" % i)
- assert failures == 0, (
- "IPv4 Zebra Routing Table verification failed for router r%s:\n%s"
- % (i, diff)
+ assert (
+ failures == 0
+ ), "IPv4 Zebra Routing Table verification failed for router r%s:\n%s" % (
+ i,
+ diff,
)
# Make sure that all daemons are running
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 0462cfbff8..68a7217dd6 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -21,6 +21,7 @@
from copy import deepcopy
from time import sleep
import traceback
+import ipaddr
import ipaddress
import os
import sys
@@ -1615,8 +1616,6 @@ def clear_bgp(tgen, addr_type, router, vrf=None):
else:
run_frr_cmd(rnode, "clear bgp *")
- sleep(5)
-
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
@@ -2115,8 +2114,8 @@ def verify_bgp_attributes(
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_bgp_attributes()")
- for router, rnode in tgen.routers().items():
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ for router, rnode in tgen.routers().iteritems():
if router != dut:
continue
@@ -2196,7 +2195,7 @@ def verify_bgp_attributes(
)
return errormsg
- logger.debug("Exiting lib API: verify_bgp_attributes()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -2516,8 +2515,9 @@ def verify_best_path_as_per_admin_distance(
return True
-@retry(attempts=6, wait=2, return_is_str=True)
-def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None):
+@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None,
+aspath=None, multi_nh=None):
"""
This API is to verify whether bgp rib has any
matching route for a nexthop.
@@ -2552,6 +2552,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
additional_nexthops_in_required_nhs = []
list1 = []
list2 = []
+ found_hops = []
for routerInput in input_dict.keys():
for router, rnode in router_list.items():
if router != dut:
@@ -2618,44 +2619,73 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
st_found = True
found_routes.append(st_rt)
- if next_hop:
+ if next_hop and multi_nh and st_found:
if not isinstance(next_hop, list):
next_hop = [next_hop]
list1 = next_hop
- found_hops = [
- rib_r["ip"]
- for rib_r in rib_routes_json["routes"][st_rt][0][
- "nexthops"
- ]
- ]
- list2 = found_hops
-
- missing_list_of_nexthops = set(list2).difference(list1)
- additional_nexthops_in_required_nhs = set(
- list1
- ).difference(list2)
+ for mnh in range(
+ 0, len(rib_routes_json["routes"][st_rt])
+ ):
+ found_hops.append(
+ [
+ rib_r["ip"]
+ for rib_r in rib_routes_json["routes"][
+ st_rt
+ ][mnh]["nexthops"]
+ ]
+ )
+ for mnh in found_hops:
+ for each_nh_in_multipath in mnh:
+ list2.append(each_nh_in_multipath)
+ if found_hops[0]:
+ missing_list_of_nexthops = set(list2).difference(
+ list1
+ )
+ additional_nexthops_in_required_nhs = set(
+ list1
+ ).difference(list2)
- if list2:
- if additional_nexthops_in_required_nhs:
- logger.info(
- "Missing nexthop %s for route"
- " %s in RIB of router %s\n",
- additional_nexthops_in_required_nhs,
- st_rt,
- dut,
- )
- errormsg = (
- "Nexthop {} is Missing for "
- "route {} in RIB of router {}\n".format(
+ if list2:
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Missing nexthop %s for route"
+ " %s in RIB of router %s\n",
additional_nexthops_in_required_nhs,
st_rt,
dut,
)
- )
return errormsg
else:
nh_found = True
+
+ elif next_hop and multi_nh is None:
+ if not isinstance(next_hop, list):
+ next_hop = [next_hop]
+ list1 = next_hop
+ found_hops = [rib_r["ip"] for rib_r in
+ rib_routes_json["routes"][
+ st_rt][0]["nexthops"]]
+ list2 = found_hops
+ missing_list_of_nexthops = \
+ set(list2).difference(list1)
+ additional_nexthops_in_required_nhs = \
+ set(list1).difference(list2)
+
+ if list2:
+ if additional_nexthops_in_required_nhs:
+ logger.info("Missing nexthop %s for route"\
+ " %s in RIB of router %s\n", \
+ additional_nexthops_in_required_nhs, \
+ st_rt, dut)
+ errormsg=("Nexthop {} is Missing for "\
+ "route {} in RIB of router {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt, dut))
+ return errormsg
+ else:
+ nh_found = True
+
if aspath:
found_paths = rib_routes_json["routes"][st_rt][0][
"path"
@@ -3678,7 +3708,6 @@ def verify_attributes_for_evpn_routes(
"""
API to verify rd and rt value using "sh bgp l2vpn evpn 10.1.1.1"
command.
-
Parameters
----------
* `tgen`: topogen object
@@ -3692,7 +3721,6 @@ def verify_attributes_for_evpn_routes(
* `ipLen` : IP prefix length
* `rd_peer` : Peer name from which RD will be auto-generated
* `rt_peer` : Peer name from which RT will be auto-generated
-
Usage
-----
input_dict_1 = {
@@ -4069,7 +4097,6 @@ def verify_evpn_routes(
"""
API to verify evpn routes using "sh bgp l2vpn evpn"
command.
-
Parameters
----------
* `tgen`: topogen object
@@ -4080,7 +4107,6 @@ def verify_evpn_routes(
* `route_type` : Route type 5 is supported as of now
* `EthTag` : Ethernet tag, by-default is 0
* `next_hop` : Prefered nexthop for the evpn routes
-
Usage
-----
input_dict_1 = {
@@ -4093,7 +4119,6 @@ def verify_evpn_routes(
}
}
result = verify_evpn_routes(tgen, topo, input_dict)
-
Returns
-------
errormsg(str) or True
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 6c24b6ddbb..70c4c061f8 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -37,7 +37,6 @@ import traceback
import socket
import ipaddress
import platform
-
if sys.version_info[0] > 2:
import configparser
else:
@@ -755,7 +754,7 @@ def start_topology(tgen, daemon=None):
def stop_router(tgen, router):
"""
- Router"s current config would be saved to /etc/frr/ for each deamon
+ Router"s current config would be saved to /tmp/topotest/<suite>/<router> for each deamon
and router and its deamons would be stopped.
* `tgen` : topogen object
@@ -774,7 +773,7 @@ def stop_router(tgen, router):
def start_router(tgen, router):
"""
- Router will started and config would be loaded from /etc/frr/ for each
+ Router will started and config would be loaded from /tmp/topotest/<suite>/<router> for each
deamon
* `tgen` : topogen object
@@ -1152,14 +1151,20 @@ def generate_ips(network, no_of_ips):
mask = int(start_ipaddr.split("/")[1])
else:
logger.debug("start_ipaddr {} must have a / in it".format(start_ipaddr))
- assert(0)
+ assert 0
addr_type = validate_ip_address(start_ip)
if addr_type == "ipv4":
- start_ip = ipaddress.IPv4Address(frr_unicode(start_ip))
+ if start_ip == "0.0.0.0" and mask == 0 and no_of_ips == 1:
+ ipaddress_list.append("{}/{}".format(start_ip, mask))
+ return ipaddress_list
+ start_ip = ipaddress.IPv4Address(unicode(start_ip))
step = 2 ** (32 - mask)
if addr_type == "ipv6":
- start_ip = ipaddress.IPv6Address(frr_unicode(start_ip))
+ if start_ip == "0::0" and mask == 0 and no_of_ips == 1:
+ ipaddress_list.append("{}/{}".format(start_ip, mask))
+ return ipaddress_list
+ start_ip = ipaddress.IPv6Address(unicode(start_ip))
step = 2 ** (128 - mask)
next_ip = start_ip
@@ -2240,6 +2245,51 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
interface_set_status(router_list[dut], intf_name, ifaceaction)
+def stop_router(tgen, router):
+ """
+ Router's current config would be saved to /tmp/topotest/<suite>/<router>
+ for each deamon and router and its deamons would be stopped.
+
+ * `tgen` : topogen object
+ * `router`: Device under test
+ """
+
+ 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")
+
+ # Stop router
+ router_list[router].stop()
+
+
+def start_router(tgen, router):
+ """
+ Router will be started and config would be loaded from
+ /tmp/topotest/<suite>/<router> for each deamon
+
+ * `tgen` : topogen object
+ * `router`: Device under test
+ """
+
+ logger.debug("Entering lib API: start_router")
+
+ try:
+ router_list = tgen.routers()
+
+ # Router and its deamons would be started and config would
+ # be loaded to router for each deamon from /etc/frr
+ router_list[router].start()
+
+ except Exception as e:
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: start_router()")
+
+
def addKernelRoute(
tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None
):
@@ -2562,7 +2612,7 @@ def verify_rib(
tag=None,
metric=None,
fib=None,
- count_only=False
+ count_only=False,
):
"""
Data will be read from input_dict or input JSON file, API will generate
@@ -2754,8 +2804,10 @@ def verify_rib(
"Nexthops are missing for "
"route {} in RIB of router {}: "
"expected {}, found {}\n".format(
- st_rt, dut, len(next_hop),
- len(found_hops)
+ st_rt,
+ dut,
+ len(next_hop),
+ len(found_hops),
)
)
return errormsg
@@ -2802,7 +2854,11 @@ def verify_rib(
errormsg = (
"[DUT: {}]: tag value {}"
" is not matched for"
- " route {} in RIB \n".format(dut, _tag, st_rt,)
+ " route {} in RIB \n".format(
+ dut,
+ _tag,
+ st_rt,
+ )
)
return errormsg
@@ -2819,7 +2875,11 @@ def verify_rib(
errormsg = (
"[DUT: {}]: metric value "
"{} is not matched for "
- "route {} in RIB \n".format(dut, metric, st_rt,)
+ "route {} in RIB \n".format(
+ dut,
+ metric,
+ st_rt,
+ )
)
return errormsg
@@ -2868,7 +2928,9 @@ def verify_rib(
for advertise_network_dict in advertise_network:
if "vrf" in advertise_network_dict:
- cmd = "{} vrf {} json".format(command, advertise_network_dict["vrf"])
+ cmd = "{} vrf {} json".format(
+ command, advertise_network_dict["vrf"]
+ )
else:
cmd = "{} json".format(command)
@@ -2947,6 +3009,7 @@ def verify_rib(
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
+
@retry(attempts=6, wait=2, return_is_str=True)
def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
"""
@@ -3327,7 +3390,12 @@ def verify_prefix_lists(tgen, input_dict):
for addr_type in prefix_lists_addr:
if not check_address_types(addr_type):
continue
-
+ # show ip prefix list
+ if addr_type == "ipv4":
+ cmd = "show ip prefix-list"
+ else:
+ cmd = "show {} prefix-list".format(addr_type)
+ show_prefix_list = run_frr_cmd(rnode, cmd)
for prefix_list in prefix_lists_addr[addr_type].keys():
if prefix_list in show_prefix_list:
errormsg = (
@@ -3550,7 +3618,6 @@ def verify_cli_json(tgen, input_dict):
"""
API to verify if JSON is available for clis
command.
-
Parameters
----------
* `tgen`: topogen object
@@ -3720,7 +3787,6 @@ def verify_vrf_vni(tgen, input_dict):
"""
API to verify vrf vni details using "show vrf vni json"
command.
-
Parameters
----------
* `tgen`: topogen object
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
index 9f3d4841b0..5c7514a641 100644
--- a/tests/topotests/lib/ospf.py
+++ b/tests/topotests/lib/ospf.py
@@ -874,7 +874,11 @@ def verify_ospf_rib(
errormsg = (
"[DUT: {}]: tag value {}"
" is not matched for"
- " route {} in RIB \n".format(dut, _tag, st_rt,)
+ " route {} in RIB \n".format(
+ dut,
+ _tag,
+ st_rt,
+ )
)
return errormsg
@@ -891,7 +895,11 @@ def verify_ospf_rib(
errormsg = (
"[DUT: {}]: metric value "
"{} is not matched for "
- "route {} in RIB \n".format(dut, metric, st_rt,)
+ "route {} in RIB \n".format(
+ dut,
+ metric,
+ st_rt,
+ )
)
return errormsg
diff --git a/tests/topotests/lib/test/test_json.py b/tests/topotests/lib/test/test_json.py
index b85e193d3b..7b3c8593cc 100755
--- a/tests/topotests/lib/test/test_json.py
+++ b/tests/topotests/lib/test/test_json.py
@@ -107,16 +107,25 @@ def test_json_intersect_multilevel_true():
dcomplete = {
"i1": "item1",
"i2": "item2",
- "i3": {"i100": "item100",},
+ "i3": {
+ "i100": "item100",
+ },
"i4": {
- "i41": {"i411": "item411",},
- "i42": {"i421": "item421", "i422": "item422",},
+ "i41": {
+ "i411": "item411",
+ },
+ "i42": {
+ "i421": "item421",
+ "i422": "item422",
+ },
},
}
dsub1 = {
"i1": "item1",
- "i3": {"i100": "item100",},
+ "i3": {
+ "i100": "item100",
+ },
"i10": None,
}
dsub2 = {
@@ -126,10 +135,36 @@ def test_json_intersect_multilevel_true():
}
dsub3 = {
"i2": "item2",
- "i4": {"i41": {"i411": "item411",}, "i42": {"i422": "item422", "i450": None,}},
+ "i4": {
+ "i41": {
+ "i411": "item411",
+ },
+ "i42": {
+ "i422": "item422",
+ "i450": None,
+ },
+ },
+ }
+ dsub4 = {
+ "i2": "item2",
+ "i4": {
+ "i41": {},
+ "i42": {
+ "i450": None,
+ },
+ },
+ }
+ dsub5 = {
+ "i2": "item2",
+ "i3": {
+ "i100": "item100",
+ },
+ "i4": {
+ "i42": {
+ "i450": None,
+ }
+ },
}
- dsub4 = {"i2": "item2", "i4": {"i41": {}, "i42": {"i450": None,}}}
- dsub5 = {"i2": "item2", "i3": {"i100": "item100",}, "i4": {"i42": {"i450": None,}}}
assert json_cmp(dcomplete, dsub1) is None
assert json_cmp(dcomplete, dsub2) is None
@@ -144,17 +179,26 @@ def test_json_intersect_multilevel_false():
dcomplete = {
"i1": "item1",
"i2": "item2",
- "i3": {"i100": "item100",},
+ "i3": {
+ "i100": "item100",
+ },
"i4": {
- "i41": {"i411": "item411",},
- "i42": {"i421": "item421", "i422": "item422",},
+ "i41": {
+ "i411": "item411",
+ },
+ "i42": {
+ "i421": "item421",
+ "i422": "item422",
+ },
},
}
# Incorrect sub-level value
dsub1 = {
"i1": "item1",
- "i3": {"i100": "item00",},
+ "i3": {
+ "i100": "item00",
+ },
"i10": None,
}
# Inexistent sub-level
@@ -166,14 +210,41 @@ def test_json_intersect_multilevel_false():
# Inexistent sub-level value
dsub3 = {
"i1": "item1",
- "i3": {"i100": None,},
+ "i3": {
+ "i100": None,
+ },
}
# Inexistent sub-sub-level value
- dsub4 = {"i4": {"i41": {"i412": "item412",}, "i42": {"i421": "item421",}}}
+ dsub4 = {
+ "i4": {
+ "i41": {
+ "i412": "item412",
+ },
+ "i42": {
+ "i421": "item421",
+ },
+ }
+ }
# Invalid sub-sub-level value
- dsub5 = {"i4": {"i41": {"i411": "item411",}, "i42": {"i421": "item420000",}}}
+ dsub5 = {
+ "i4": {
+ "i41": {
+ "i411": "item411",
+ },
+ "i42": {
+ "i421": "item420000",
+ },
+ }
+ }
# sub-sub-level should be value
- dsub6 = {"i4": {"i41": {"i411": "item411",}, "i42": "foobar",}}
+ dsub6 = {
+ "i4": {
+ "i41": {
+ "i411": "item411",
+ },
+ "i42": "foobar",
+ }
+ }
assert json_cmp(dcomplete, dsub1) is not None
assert json_cmp(dcomplete, dsub2) is not None
@@ -187,7 +258,15 @@ def test_json_with_list_sucess():
"Test successful json comparisons that have lists."
dcomplete = {
- "list": [{"i1": "item 1", "i2": "item 2",}, {"i10": "item 10",},],
+ "list": [
+ {
+ "i1": "item 1",
+ "i2": "item 2",
+ },
+ {
+ "i10": "item 10",
+ },
+ ],
"i100": "item 100",
}
@@ -197,12 +276,19 @@ def test_json_with_list_sucess():
}
# Test list correct list items
dsub2 = {
- "list": [{"i1": "item 1",},],
+ "list": [
+ {
+ "i1": "item 1",
+ },
+ ],
"i100": "item 100",
}
# Test list correct list size
dsub3 = {
- "list": [{}, {},],
+ "list": [
+ {},
+ {},
+ ],
}
assert json_cmp(dcomplete, dsub1) is None
@@ -214,7 +300,15 @@ def test_json_with_list_failure():
"Test failed json comparisons that have lists."
dcomplete = {
- "list": [{"i1": "item 1", "i2": "item 2",}, {"i10": "item 10",},],
+ "list": [
+ {
+ "i1": "item 1",
+ "i2": "item 2",
+ },
+ {
+ "i10": "item 10",
+ },
+ ],
"i100": "item 100",
}
@@ -224,12 +318,20 @@ def test_json_with_list_failure():
}
# Test list incorrect list items
dsub2 = {
- "list": [{"i1": "item 2",},],
+ "list": [
+ {
+ "i1": "item 2",
+ },
+ ],
"i100": "item 100",
}
# Test list correct list size
dsub3 = {
- "list": [{}, {}, {},],
+ "list": [
+ {},
+ {},
+ {},
+ ],
}
assert json_cmp(dcomplete, dsub1) is not None
@@ -241,20 +343,52 @@ def test_json_list_start_success():
"Test JSON encoded data that starts with a list that should succeed."
dcomplete = [
- {"id": 100, "value": "abc",},
- {"id": 200, "value": "abcd",},
- {"id": 300, "value": "abcde",},
+ {
+ "id": 100,
+ "value": "abc",
+ },
+ {
+ "id": 200,
+ "value": "abcd",
+ },
+ {
+ "id": 300,
+ "value": "abcde",
+ },
]
- dsub1 = [{"id": 100, "value": "abc",}]
+ dsub1 = [
+ {
+ "id": 100,
+ "value": "abc",
+ }
+ ]
- dsub2 = [{"id": 100, "value": "abc",}, {"id": 200, "value": "abcd",}]
+ dsub2 = [
+ {
+ "id": 100,
+ "value": "abc",
+ },
+ {
+ "id": 200,
+ "value": "abcd",
+ },
+ ]
- dsub3 = [{"id": 300, "value": "abcde",}]
+ dsub3 = [
+ {
+ "id": 300,
+ "value": "abcde",
+ }
+ ]
dsub4 = []
- dsub5 = [{"id": 100,}]
+ dsub5 = [
+ {
+ "id": 100,
+ }
+ ]
assert json_cmp(dcomplete, dsub1) is None
assert json_cmp(dcomplete, dsub2) is None
@@ -272,13 +406,44 @@ def test_json_list_start_failure():
{"id": 300, "value": "abcde"},
]
- dsub1 = [{"id": 100, "value": "abcd",}]
+ dsub1 = [
+ {
+ "id": 100,
+ "value": "abcd",
+ }
+ ]
- dsub2 = [{"id": 100, "value": "abc",}, {"id": 200, "value": "abc",}]
+ dsub2 = [
+ {
+ "id": 100,
+ "value": "abc",
+ },
+ {
+ "id": 200,
+ "value": "abc",
+ },
+ ]
- dsub3 = [{"id": 100, "value": "abc",}, {"id": 350, "value": "abcde",}]
+ dsub3 = [
+ {
+ "id": 100,
+ "value": "abc",
+ },
+ {
+ "id": 350,
+ "value": "abcde",
+ },
+ ]
- dsub4 = [{"value": "abcx",}, {"id": 300, "value": "abcde",}]
+ dsub4 = [
+ {
+ "value": "abcx",
+ },
+ {
+ "id": 300,
+ "value": "abcde",
+ },
+ ]
assert json_cmp(dcomplete, dsub1) is not None
assert json_cmp(dcomplete, dsub2) is not None
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index 86f06b2af7..7c52e824c1 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -336,7 +336,9 @@ class Topogen(object):
for gear in self.gears.values():
errors += gear.stop()
if len(errors) > 0:
- logger.error("Errors found post shutdown - details follow: {}".format(errors))
+ logger.error(
+ "Errors found post shutdown - details follow: {}".format(errors)
+ )
self.net.stop()
diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py
index f2fafa5e2a..0e59f90a20 100644
--- a/tests/topotests/lib/topojson.py
+++ b/tests/topotests/lib/topojson.py
@@ -96,6 +96,7 @@ def build_topo_from_json(tgen, topo):
for router in listRouters:
topo["routers"][router]["nextIfname"] = 0
+ router_count = 0
while listRouters != []:
curRouter = listRouters.pop(0)
# Physical Interfaces
@@ -116,13 +117,14 @@ def build_topo_from_json(tgen, topo):
currRouter_lo_json = topo["routers"][curRouter]["links"][destRouterLink]
# Loopback interfaces
if "type" in data and data["type"] == "loopback":
+ router_count += 1
if (
"ipv4" in currRouter_lo_json
and currRouter_lo_json["ipv4"] == "auto"
):
currRouter_lo_json["ipv4"] = "{}{}.{}/{}".format(
topo["lo_prefix"]["ipv4"],
- number_to_row(curRouter),
+ router_count,
number_to_column(curRouter),
topo["lo_prefix"]["v4mask"],
)
@@ -132,7 +134,7 @@ def build_topo_from_json(tgen, topo):
):
currRouter_lo_json["ipv6"] = "{}{}:{}/{}".format(
topo["lo_prefix"]["ipv6"],
- number_to_row(curRouter),
+ router_count,
number_to_column(curRouter),
topo["lo_prefix"]["v6mask"],
)
@@ -167,6 +169,14 @@ def build_topo_from_json(tgen, topo):
destRouter, curRouter, topo["routers"][destRouter]["nextIfname"]
)
+ # add link interface
+ destRouter_link_json["peer-interface"] = "{}-{}-eth{}".format(
+ curRouter, destRouter, topo["routers"][curRouter]["nextIfname"]
+ )
+ currRouter_link_json["peer-interface"] = "{}-{}-eth{}".format(
+ destRouter, curRouter, topo["routers"][destRouter]["nextIfname"]
+ )
+
topo["routers"][curRouter]["nextIfname"] += 1
topo["routers"][destRouter]["nextIfname"] += 1
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index d1e76866a7..ef0ac27118 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -609,8 +609,10 @@ def interface_set_status(node, ifacename, ifaceaction=False, vrf_name=None):
ifacename, str_ifaceaction
)
else:
- cmd = 'vtysh -c "configure terminal" -c "interface {0} vrf {1}" -c "{2}"'.format(
- ifacename, vrf_name, str_ifaceaction
+ cmd = (
+ 'vtysh -c "configure terminal" -c "interface {0} vrf {1}" -c "{2}"'.format(
+ ifacename, vrf_name, str_ifaceaction
+ )
)
node.run(cmd)
@@ -924,40 +926,44 @@ def checkAddressSanitizerError(output, router, component, logdir=""):
)
if addressSanitizerLog:
# Find Calling Test. Could be multiple steps back
- testframe=sys._current_frames().values()[0]
- level=0
+ testframe = sys._current_frames().values()[0]
+ level = 0
while level < 10:
- test=os.path.splitext(os.path.basename(testframe.f_globals["__file__"]))[0]
+ test = os.path.splitext(
+ os.path.basename(testframe.f_globals["__file__"])
+ )[0]
if (test != "topotest") and (test != "topogen"):
# Found the calling test
- callingTest=os.path.basename(testframe.f_globals["__file__"])
+ callingTest = os.path.basename(testframe.f_globals["__file__"])
break
- level=level+1
- testframe=testframe.f_back
- if (level >= 10):
+ level = level + 1
+ testframe = testframe.f_back
+ if level >= 10:
# somehow couldn't find the test script.
- callingTest="unknownTest"
+ callingTest = "unknownTest"
#
# Now finding Calling Procedure
- level=0
+ level = 0
while level < 20:
- callingProc=sys._getframe(level).f_code.co_name
- if ((callingProc != "processAddressSanitizerError") and
- (callingProc != "checkAddressSanitizerError") and
- (callingProc != "checkRouterCores") and
- (callingProc != "stopRouter") and
- (callingProc != "__stop_internal") and
- (callingProc != "stop") and
- (callingProc != "stop_topology") and
- (callingProc != "checkRouterRunning") and
- (callingProc != "check_router_running") and
- (callingProc != "routers_have_failure")):
+ callingProc = sys._getframe(level).f_code.co_name
+ if (
+ (callingProc != "processAddressSanitizerError")
+ and (callingProc != "checkAddressSanitizerError")
+ and (callingProc != "checkRouterCores")
+ and (callingProc != "stopRouter")
+ and (callingProc != "__stop_internal")
+ and (callingProc != "stop")
+ and (callingProc != "stop_topology")
+ and (callingProc != "checkRouterRunning")
+ and (callingProc != "check_router_running")
+ and (callingProc != "routers_have_failure")
+ ):
# Found the calling test
break
- level=level+1
- if (level >= 20):
+ level = level + 1
+ if level >= 20:
# something wrong - couldn't found the calling test function
- callingProc="unknownProc"
+ callingProc = "unknownProc"
with open("/tmp/AddressSanitzer.txt", "a") as addrSanFile:
sys.stderr.write(
"AddressSanitizer error in topotest `%s`, test `%s`, router `%s`\n\n"
@@ -979,7 +985,6 @@ def checkAddressSanitizerError(output, router, component, logdir=""):
addrSanFile.write("\n---------------\n")
return
-
addressSanitizerError = re.search(
"(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ", output
)
@@ -989,16 +994,20 @@ def checkAddressSanitizerError(output, router, component, logdir=""):
# No Address Sanitizer Error in Output. Now check for AddressSanitizer daemon file
if logdir:
- filepattern=logdir+"/"+router+"/"+component+".asan.*"
- logger.debug("Log check for %s on %s, pattern %s\n" % (component, router, filepattern))
+ filepattern = logdir + "/" + router + "/" + component + ".asan.*"
+ logger.debug(
+ "Log check for %s on %s, pattern %s\n" % (component, router, filepattern)
+ )
for file in glob.glob(filepattern):
with open(file, "r") as asanErrorFile:
- asanError=asanErrorFile.read()
+ asanError = asanErrorFile.read()
addressSanitizerError = re.search(
"(==[0-9]+==)ERROR: AddressSanitizer: ([^\s]*) ", asanError
- )
+ )
if addressSanitizerError:
- processAddressSanitizerError(addressSanitizerError, asanError, router, component)
+ processAddressSanitizerError(
+ addressSanitizerError, asanError, router, component
+ )
return True
return False
@@ -1065,7 +1074,7 @@ class Router(Node):
if self.logdir is None:
cur_test = os.environ["PYTEST_CURRENT_TEST"]
self.logdir = "/tmp/topotests/" + cur_test[
- cur_test.find("/")+1 : cur_test.find(".py")
+ cur_test.find("/") + 1 : cur_test.find(".py")
].replace("/", ".")
# If the logdir is not created, then create it and set the
@@ -1073,7 +1082,7 @@ class Router(Node):
if not os.path.isdir(self.logdir):
os.system("mkdir -p " + self.logdir + "/" + name)
os.system("chmod -R go+rw /tmp/topotests")
- # Erase logs of previous run
+ # Erase logs of previous run
os.system("rm -rf " + self.logdir + "/" + name)
self.daemondir = None
diff --git a/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py b/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py
index 6d44d02e5e..2421b312d2 100644
--- a/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py
+++ b/tests/topotests/ospf-topo1-vrf/test_ospf_topo1_vrf.py
@@ -320,8 +320,10 @@ def test_ospf_link_down_kernel_route():
# Run test function until we get an result. Wait at most 60 seconds.
test_func = partial(compare_show_ip_route_vrf, router.name, expected)
result, diff = topotest.run_and_expect(test_func, "", count=140, wait=0.5)
- assertmsg = 'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format(
- router.name, diff
+ assertmsg = (
+ 'OSPF IPv4 route mismatch in router "{}" after link down: {}'.format(
+ router.name, diff
+ )
)
assert result, assertmsg
diff --git a/tests/topotests/ospf-topo1/test_ospf_topo1.py b/tests/topotests/ospf-topo1/test_ospf_topo1.py
index 95193afb2a..24806dd8fc 100644
--- a/tests/topotests/ospf-topo1/test_ospf_topo1.py
+++ b/tests/topotests/ospf-topo1/test_ospf_topo1.py
@@ -310,7 +310,10 @@ def test_ospf_json():
# r4 has more interfaces for area 0.0.0.1
if router.name == "r4":
expected["areas"]["0.0.0.1"].update(
- {"areaIfActiveCounter": 2, "areaIfTotalCounter": 2,}
+ {
+ "areaIfActiveCounter": 2,
+ "areaIfTotalCounter": 2,
+ }
)
# router 3 has an additional area
@@ -372,16 +375,25 @@ def test_ospf_link_down_kernel_route():
}
if router.name == "r1" or router.name == "r2":
expected.update(
- {"10.0.10.0/24": None, "172.16.0.0/24": None, "172.16.1.0/24": None,}
+ {
+ "10.0.10.0/24": None,
+ "172.16.0.0/24": None,
+ "172.16.1.0/24": None,
+ }
)
elif router.name == "r3" or router.name == "r4":
expected.update(
- {"10.0.1.0/24": None, "10.0.2.0/24": None,}
+ {
+ "10.0.1.0/24": None,
+ "10.0.2.0/24": None,
+ }
)
# Route '10.0.3.0' is no longer available for r4 since it is down.
if router.name == "r4":
expected.update(
- {"10.0.3.0/24": None,}
+ {
+ "10.0.3.0/24": None,
+ }
)
assertmsg = 'OSPF IPv4 route mismatch in router "{}" after link down'.format(
router.name
@@ -443,12 +455,17 @@ def test_ospf6_link_down_kernel_route():
)
elif router.name == "r3" or router.name == "r4":
expected.update(
- {"2001:db8:1::/64": None, "2001:db8:2::/64": None,}
+ {
+ "2001:db8:1::/64": None,
+ "2001:db8:2::/64": None,
+ }
)
# Route '2001:db8:3::/64' is no longer available for r4 since it is down.
if router.name == "r4":
expected.update(
- {"2001:db8:3::/64": None,}
+ {
+ "2001:db8:3::/64": None,
+ }
)
assertmsg = 'OSPF IPv6 route mismatch in router "{}" after link down'.format(
router.name
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
index 3b37b8a92f..5ef6b9b0be 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
@@ -252,7 +252,11 @@ def test_ospf_ecmp_tc16_p0(request):
input_dict = {
"r0": {
"static_routes": [
- {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 5,
+ "next_hop": "Null0",
+ }
]
}
}
@@ -415,7 +419,11 @@ def test_ospf_ecmp_tc17_p0(request):
input_dict = {
"r0": {
"static_routes": [
- {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 5,
+ "next_hop": "Null0",
+ }
]
}
}
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
index 04b1f4b878..88667a6ac8 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
@@ -197,6 +197,7 @@ def teardown_module(mod):
# Test cases start here.
# ##################################
+
def test_ospf_routemaps_functionality_tc19_p0(request):
"""
OSPF Route map - Verify OSPF route map support functionality.
@@ -215,121 +216,92 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
"r0": {
"static_routes": [
{
- "network": NETWORK['ipv4'][0],
+ "network": NETWORK["ipv4"][0],
"no_of_ip": 5,
- "next_hop": 'Null0',
+ "next_hop": "Null0",
}
]
}
}
result = create_static_routes(tgen, 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)
- ospf_red_r1 = {
- "r0": {
- "ospf": {
- "redistribute": [{
- "redist_type": "static"
- }]
- }
- }
- }
+ ospf_red_r1 = {"r0": {"ospf": {"redistribute": [{"redist_type": "static"}]}}}
result = create_router_ospf(tgen, topo, ospf_red_r1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- dut = 'r1'
- lsid = NETWORK['ipv4'][0].split("/")[0]
- rid = routerids[0]
- protocol = 'ospf'
+ dut = "r1"
+ lsid = NETWORK["ipv4"][0].split("/")[0]
+ rid = routerids[0]
+ protocol = "ospf"
result = verify_ospf_rib(tgen, 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, "ipv4", dut, input_dict, protocol=protocol)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
ospf_red_r1 = {
"r0": {
- "ospf": {
- "redistribute": [{
- "redist_type": "static",
- "del_action": True
- }]
- }
+ "ospf": {"redistribute": [{"redist_type": "static", "del_action": True}]}
}
}
result = create_router_ospf(tgen, topo, ospf_red_r1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
- 'Create prefix-list in R0 to permit 10.0.20.1/32 prefix &'
- ' deny 10.0.20.2/32')
+ "Create prefix-list in R0 to permit 10.0.20.1/32 prefix &" " deny 10.0.20.2/32"
+ )
# Create ip prefix list
pfx_list = {
"r0": {
"prefix_lists": {
"ipv4": {
- "pf_list_1_ipv4": [{
- "seqid": 10,
- "network": NETWORK['ipv4'][0],
- "action": "permit"
- },
- {
- "seqid": 11,
- "network": "any",
- "action": "deny"
- }
+ "pf_list_1_ipv4": [
+ {
+ "seqid": 10,
+ "network": NETWORK["ipv4"][0],
+ "action": "permit",
+ },
+ {"seqid": 11, "network": "any", "action": "deny"},
]
}
}
}
}
result = create_prefix_lists(tgen, pfx_list)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
# Create route map
routemaps = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [
+ {
"action": "permit",
- "match": {
- "ipv4": {
- "prefix_lists":
- "pf_list_1_ipv4"
- }
- }
- }]
- }
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ }
+ ]
}
+ }
}
result = create_route_maps(tgen, routemaps)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Configure route map rmap1 and redistribute static routes to"
- " ospf using route map rmap1")
+ " ospf using route map rmap1"
+ )
ospf_red_r1 = {
"r0": {
"ospf": {
- "redistribute": [{
- "redist_type": "static",
- "route_map": "rmap_ipv4"
- }]
+ "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red_r1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Change prefix rules to permit 10.0.20.2 and deny 10.0.20.1")
# Create ip prefix list
@@ -337,65 +309,54 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
"r0": {
"prefix_lists": {
"ipv4": {
- "pf_list_1_ipv4": [{
- "seqid": 10,
- "network": NETWORK['ipv4'][1],
- "action": "permit"
- },
- {
- "seqid": 11,
- "network": "any",
- "action": "deny"
- }
+ "pf_list_1_ipv4": [
+ {
+ "seqid": 10,
+ "network": NETWORK["ipv4"][1],
+ "action": "permit",
+ },
+ {"seqid": 11, "network": "any", "action": "deny"},
]
}
}
}
}
result = create_prefix_lists(tgen, pfx_list)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that route 10.0.20.2 is allowed and 10.0.20.1 is denied.")
- dut = 'r1'
+ dut = "r1"
input_dict = {
"r0": {
"static_routes": [
- {
- "network": NETWORK['ipv4'][1],
- "no_of_ip": 1,
- "next_hop": 'Null0'
- }
+ {"network": NETWORK["ipv4"][1], "no_of_ip": 1, "next_hop": "Null0"}
]
}
}
result = verify_ospf_rib(tgen, 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, "ipv4", dut, input_dict, protocol=protocol)
- 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 = {
"r0": {
"static_routes": [
- {
- "network": NETWORK['ipv4'][0],
- "no_of_ip": 1,
- "next_hop": 'Null0'
- }
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0"}
]
}
}
result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ tc_name, result
+ )
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
- expected=False)
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+ )
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ tc_name, result
+ )
step("Delete and reconfigure prefix list.")
# Create ip prefix list
@@ -403,114 +364,101 @@ def test_ospf_routemaps_functionality_tc19_p0(request):
"r0": {
"prefix_lists": {
"ipv4": {
- "pf_list_1_ipv4": [{
- "seqid": 10,
- "network": NETWORK['ipv4'][1],
- "action": "permit",
- "delete": True
- },
- {
- "seqid": 11,
- "network": "any",
- "action": "deny",
- "delete": True
- }
+ "pf_list_1_ipv4": [
+ {
+ "seqid": 10,
+ "network": NETWORK["ipv4"][1],
+ "action": "permit",
+ "delete": True,
+ },
+ {
+ "seqid": 11,
+ "network": "any",
+ "action": "deny",
+ "delete": True,
+ },
]
}
}
}
}
result = create_prefix_lists(tgen, pfx_list)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
result = verify_prefix_lists(tgen, pfx_list)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
input_dict = {
"r0": {
"static_routes": [
- {
- "network": NETWORK['ipv4'][0],
- "no_of_ip": 5,
- "next_hop": 'Null0'
- }
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0"}
]
}
}
result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ tc_name, result
+ )
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
- expected=False)
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+ )
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ tc_name, result
+ )
pfx_list = {
"r0": {
"prefix_lists": {
"ipv4": {
- "pf_list_1_ipv4": [{
- "seqid": 10,
- "network": NETWORK['ipv4'][1],
- "action": "permit"
- },
- {
- "seqid": 11,
- "network": "any",
- "action": "deny"
- }
+ "pf_list_1_ipv4": [
+ {
+ "seqid": 10,
+ "network": NETWORK["ipv4"][1],
+ "action": "permit",
+ },
+ {"seqid": 11, "network": "any", "action": "deny"},
]
}
}
}
}
result = create_prefix_lists(tgen, pfx_list)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that route 10.0.20.2 is allowed and 10.0.20.1 is denied.")
- dut = 'r1'
+ dut = "r1"
input_dict = {
"r0": {
"static_routes": [
- {
- "network": NETWORK['ipv4'][1],
- "no_of_ip": 1,
- "next_hop": 'Null0'
- }
+ {"network": NETWORK["ipv4"][1], "no_of_ip": 1, "next_hop": "Null0"}
]
}
}
result = verify_ospf_rib(tgen, 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, "ipv4", dut, input_dict, protocol=protocol)
- 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 = {
"r0": {
"static_routes": [
- {
- "network": NETWORK['ipv4'][0],
- "no_of_ip": 1,
- "next_hop": 'Null0'
- }
+ {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0"}
]
}
}
result = verify_ospf_rib(tgen, dut, input_dict, expected=False)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ tc_name, result
+ )
- result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol,
- expected=False)
+ result = verify_rib(
+ tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
+ )
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ tc_name, result
+ )
write_test_footer(tc_name)
@@ -535,7 +483,11 @@ def test_ospf_routemaps_functionality_tc20_p0(request):
input_dict = {
"r0": {
"static_routes": [
- {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 5,
+ "next_hop": "Null0",
+ }
]
}
}
@@ -663,318 +615,229 @@ def test_ospf_routemaps_functionality_tc21_p0(request):
step(
"Create static routes(10.0.20.1/32) in R1 and redistribute "
- "to OSPF using route map.")
+ "to OSPF using route map."
+ )
# Create Static routes
input_dict = {
"r0": {
"static_routes": [
{
- "network": NETWORK['ipv4'][0],
+ "network": NETWORK["ipv4"][0],
"no_of_ip": 5,
- "next_hop": 'Null0',
+ "next_hop": "Null0",
}
]
}
}
result = create_static_routes(tgen, 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)
ospf_red_r0 = {
"r0": {
"ospf": {
- "redistribute": [{
- "redist_type": "static",
- "route_map": "rmap_ipv4"
- }]
+ "redistribute": [{"redist_type": "static", "route_map": "rmap_ipv4"}]
}
}
}
result = create_router_ospf(tgen, topo, ospf_red_r0)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
# Create route map
routemaps = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
- "action": "permit",
- "seq_id": 10
- }]
- }
- }
+ "r0": {"route_maps": {"rmap_ipv4": [{"action": "permit", "seq_id": 10}]}}
}
result = create_route_maps(tgen, routemaps)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that route is advertised to R2.")
- dut = 'r1'
- protocol = 'ospf'
+ dut = "r1"
+ protocol = "ospf"
result = verify_ospf_rib(tgen, 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, "ipv4", dut, input_dict, protocol=protocol)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
# Create route map
routemaps = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
- "action": "permit",
- "delete": True,
- "seq_id": 10
- }]
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [{"action": "permit", "delete": True, "seq_id": 10}]
+ }
}
}
- }
result = create_route_maps(tgen, routemaps)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- step(' Configure route map with set clause (set metric)')
+ step(" Configure route map with set clause (set metric)")
# Create route map
routemaps = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
- "action": "permit",
- "set": {
- "med": 123
- },
- "seq_id": 10
- }]
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [{"action": "permit", "set": {"med": 123}, "seq_id": 10}]
+ }
}
}
- }
result = create_route_maps(tgen, routemaps)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Verify that configured metric is applied to ospf routes.")
- dut = 'r1'
- protocol = 'ospf'
+ dut = "r1"
+ protocol = "ospf"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol=protocol)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"Configure route map with match clause (match metric) with "
- "some actions(change metric).")
+ "some actions(change metric)."
+ )
# Create route map
routemaps = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
- "action": "permit",
- "match": {
- "med": 123
- },
- "set": {
- "med": 150
- },
- "seq_id": 10
- }]
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [
+ {
+ "action": "permit",
+ "match": {"med": 123},
+ "set": {"med": 150},
+ "seq_id": 10,
+ }
+ ]
+ }
}
}
- }
result = create_route_maps(tgen, routemaps)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Configure route map with call clause")
# Create ip prefix list
input_dict_2 = {
- 'r0': {
- 'prefix_lists': {
- 'ipv4': {
- 'pf_list_1_ipv4': [{
- 'seqid': 10,
- 'network': 'any',
- 'action': 'permit'
- }]
- }
+ "r0": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [
+ {"seqid": 10, "network": "any", "action": "permit"}
+ ]
+ }
}
}
}
result = create_prefix_lists(tgen, input_dict_2)
- assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
# Create route map
input_dict_3 = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
- "action": "permit",
- "match": {
- "ipv4": {
- "prefix_lists": "pf_list_1_ipv4"
- }
- },
- "set": {
- "med": 150
- },
- "call": "rmap_match_pf_2_ipv4",
- "seq_id": 10
- }],
- "rmap_match_pf_2_ipv4": [{
- "action": "permit",
- "match": {
- "ipv4": {
- "prefix_lists": "pf_list_1_ipv4"
- }
- },
- "set": {
- "med": 200
- },
- "seq_id": 10
- }]
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [
+ {
+ "action": "permit",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ "set": {"med": 150},
+ "call": "rmap_match_pf_2_ipv4",
+ "seq_id": 10,
+ }
+ ],
+ "rmap_match_pf_2_ipv4": [
+ {
+ "action": "permit",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ "set": {"med": 200},
+ "seq_id": 10,
+ }
+ ],
+ }
}
}
- }
result = create_route_maps(tgen, input_dict_3)
- 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_ospf_rib(tgen, 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, "ipv4", dut, input_dict, protocol=protocol)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
# Create route map
- routemaps = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
- "delete": True
- }]
- }
- }
- }
+ routemaps = {"r0": {"route_maps": {"rmap_ipv4": [{"delete": True}]}}}
result = create_route_maps(tgen, routemaps)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Configure route map with continue clause")
# Create route map
input_dict_3 = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
- "action": "permit",
- 'seq_id': '10',
- "match": {
- "ipv4": {
- "prefix_lists": "pf_list_1_ipv4"
- }
- },
- "set": {
- "med": 150
- },
- "continue": "30",
- "seq_id": 10
- },
- {
- "action": "permit",
- "match": {
- "ipv4": {
- "prefix_lists": "pf_list_1_ipv4"
- }
- },
- "set": {
- "med": 100
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ "set": {"med": 150},
+ "continue": "30",
+ "seq_id": 10,
},
- "seq_id": 20
- },
- {
- "action": "permit",
- "match": {
- "ipv4": {
- "prefix_lists": "pf_list_1_ipv4"
- }
+ {
+ "action": "permit",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ "set": {"med": 100},
+ "seq_id": 20,
},
- "set": {
- "med": 50
+ {
+ "action": "permit",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ "set": {"med": 50},
+ "seq_id": 30,
},
- "seq_id": 30
- }
- ]
+ ]
+ }
}
}
- }
result = create_route_maps(tgen, input_dict_3)
- 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_ospf_rib(tgen, 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, "ipv4", dut, input_dict, protocol=protocol)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("Configure route map with goto clause")
# Create route map
input_dict_3 = {
- "r0": {
- "route_maps": {
- "rmap_ipv4": [{
- "action": "permit",
- 'seq_id': '10',
- "match": {
- "ipv4": {
- "prefix_lists": "pf_list_1_ipv4"
- }
+ "r0": {
+ "route_maps": {
+ "rmap_ipv4": [
+ {
+ "action": "permit",
+ "seq_id": "10",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ "goto": "30",
},
- "goto": "30",
- },
- {
- "action": "permit",
- 'seq_id': '20',
- "match": {
- "ipv4": {
- "prefix_lists": "pf_list_1_ipv4"
- }
+ {
+ "action": "permit",
+ "seq_id": "20",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ "set": {"med": 100},
},
- "set": {
- "med": 100
- }
- },
- {
- "action": "permit",
- 'seq_id': '30',
- "match": {
- "ipv4": {
- "prefix_lists": "pf_list_1_ipv4"
- }
+ {
+ "action": "permit",
+ "seq_id": "30",
+ "match": {"ipv4": {"prefix_lists": "pf_list_1_ipv4"}},
+ "set": {"med": 200},
},
- "set": {
- "med": 200
- }
- }
- ]
+ ]
+ }
}
}
- }
result = create_route_maps(tgen, input_dict_3)
- 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, "ipv4", dut, input_dict, protocol=protocol)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
@@ -1003,7 +866,11 @@ def test_ospf_routemaps_functionality_tc24_p0(request):
input_dict = {
"r0": {
"static_routes": [
- {"network": NETWORK["ipv4"][0], "no_of_ip": 1, "next_hop": "Null0",}
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 1,
+ "next_hop": "Null0",
+ }
]
}
}
@@ -1037,9 +904,10 @@ def test_ospf_routemaps_functionality_tc24_p0(request):
step("verify that prefix-list is created in R0.")
result = verify_prefix_lists(tgen, pfx_list)
- assert result is not True, (
- "Testcase {} : Failed \n Prefix list not "
- "present. Error: {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Prefix list not " "present. Error: {}".format(
+ tc_name, result
)
# Create route map
@@ -1105,9 +973,10 @@ def test_ospf_routemaps_functionality_tc24_p0(request):
step("verify that prefix-list is created in R0.")
result = verify_prefix_lists(tgen, pfx_list)
- assert result is not True, (
- "Testcase {} : Failed \n Prefix list not "
- "present. Error: {}".format(tc_name, result)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Prefix list not " "present. Error: {}".format(
+ tc_name, result
)
# Create route map
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
index 6ac0b515df..434d7f8ef5 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
@@ -407,7 +407,13 @@ def test_ospf_redistribution_tc6_p0(request):
protocol = "ospf"
result = verify_rib(
- tgen, "ipv4", dut, input_dict, protocol=protocol, next_hop=nh, expected=False,
+ tgen,
+ "ipv4",
+ dut,
+ input_dict,
+ protocol=protocol,
+ next_hop=nh,
+ expected=False,
)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
tc_name, result
@@ -549,7 +555,11 @@ def test_ospf_redistribution_tc8_p1(request):
input_dict = {
"r0": {
"static_routes": [
- {"network": NETWORK["ipv4"][0], "no_of_ip": 5, "next_hop": "Null0",}
+ {
+ "network": NETWORK["ipv4"][0],
+ "no_of_ip": 5,
+ "next_hop": "Null0",
+ }
]
}
}
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
index b2b0fb8d44..6f6b119abc 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py
@@ -777,7 +777,6 @@ def test_ospf_show_p1(request):
write_test_footer(tc_name)
-
def test_ospf_dead_tc11_p0(request):
"""
OSPF timers.
@@ -799,224 +798,146 @@ def test_ospf_dead_tc11_p0(request):
step("modify dead interval from default value to some other value on r1")
topo1 = {
- 'r1': {
- 'links': {
- 'r0': {
- 'interface': topo['routers']['r1']['links']['r0'][
- 'interface'],
- 'ospf': {
- 'hello_interval': 12,
- 'dead_interval': 48
- }
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"hello_interval": 12, "dead_interval": 48},
}
}
}
}
-
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
"verify that new timer value is configured and applied using "
- "the show ip ospf interface command.")
- dut = 'r1'
- input_dict= {
- 'r1': {
- 'links':{
- 'r0': {
- 'ospf':{
- 'timerDeadSecs': 48
- }
- }
- }
- }
- }
+ "the show ip ospf interface command."
+ )
+ dut = "r1"
+ input_dict = {"r1": {"links": {"r0": {"ospf": {"timerDeadSecs": 48}}}}}
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=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)
- step(
- "modify dead interval from default value to r1"
- "dead interval timer on r2")
+ step("modify dead interval from default value to r1" "dead interval timer on r2")
topo1 = {
- 'r0': {
- 'links': {
- 'r1': {
- 'interface': topo['routers']['r0']['links']['r1'][
- 'interface'],
- 'ospf': {
- 'dead_interval': 48,
- 'hello_interval': 12
- }
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"dead_interval": 48, "hello_interval": 12},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
-
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that new timer value is configured.")
- input_dict= {
- 'r0': {
- 'links':{
- 'r1': {
- 'ospf':{
- 'timerDeadSecs': 48
- }
- }
- }
- }
- }
- dut = 'r0'
+ input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 48}}}}}
+ dut = "r0"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
- assert ospf_covergence is True, ("setup_module :Failed \n Error:"
- " {}".format(ospf_covergence))
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
- step(
- "reconfigure the default dead interval timer value to "
- "default on r1 and r2")
+ step("reconfigure the default dead interval timer value to " "default on r1 and r2")
topo1 = {
- 'r0': {
- 'links': {
- 'r1': {
- 'interface': topo['routers']['r0']['links']['r1'][
- 'interface'],
- 'ospf': {
- 'dead_interval': 40
- }
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"dead_interval": 40},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo1 = {
- 'r1': {
- 'links': {
- 'r0': {
- 'interface': topo['routers']['r1']['links']['r0'][
- 'interface'],
- 'ospf': {
- 'dead_interval': 40
- }
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"dead_interval": 40},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that new timer value is configured.")
- input_dict= {
- 'r0': {
- 'links':{
- 'r1': {
- 'ospf':{
- 'timerDeadSecs': 40
- }
- }
- }
- }
- }
- dut = 'r0'
+ input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 40}}}}}
+ dut = "r0"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
-
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
- assert ospf_covergence is True, ("setup_module :Failed \n Error:"
- " {}".format(ospf_covergence))
-
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
step(" Configure dead timer = 65535 on r1 and r2")
topo1 = {
- 'r0': {
- 'links': {
- 'r1': {
- 'interface': topo['routers']['r0']['links']['r1'][
- 'interface'],
- 'ospf': {
- 'dead_interval': 65535
- }
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"dead_interval": 65535},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
topo1 = {
- 'r1': {
- 'links': {
- 'r0': {
- 'interface': topo['routers']['r1']['links']['r0'][
- 'interface'],
- 'ospf': {
- 'dead_interval': 65535
- }
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"dead_interval": 65535},
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that new timer value is configured.")
- input_dict= {
- 'r0': {
- 'links':{
- 'r1': {
- 'ospf':{
- 'timerDeadSecs': 65535
- }
- }
- }
- }
- }
- dut = 'r0'
+ input_dict = {"r0": {"links": {"r1": {"ospf": {"timerDeadSecs": 65535}}}}}
+ dut = "r0"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step("verify that ospf neighbours are full")
ospf_covergence = verify_ospf_neighbor(tgen, topo, dut=dut)
- assert ospf_covergence is True, ("setup_module :Failed \n Error:"
- " {}".format(ospf_covergence))
-
+ assert ospf_covergence is True, "setup_module :Failed \n Error:" " {}".format(
+ ospf_covergence
+ )
step(" Try configuring timer values outside range for example 65536")
topo1 = {
- 'r0': {
- 'links': {
- 'r1': {
- 'interface': topo['routers']['r0']['links']['r1'][
- 'interface'],
- 'ospf': {
- 'dead_interval': 65536
- }
+ "r0": {
+ "links": {
+ "r1": {
+ "interface": topo["routers"]["r0"]["links"]["r1"]["interface"],
+ "ospf": {"dead_interval": 65536},
}
}
}
@@ -1024,47 +945,33 @@ def test_ospf_dead_tc11_p0(request):
result = create_interfaces_cfg(tgen, topo1)
assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ tc_name, result
+ )
step("Unconfigure the dead timer from the interface from r1 and r2.")
topo1 = {
- 'r1': {
- 'links': {
- 'r0': {
- 'interface': topo['routers']['r1']['links']['r0'][
- 'interface'],
- 'ospf': {
- 'dead_interval': 65535
- },
- 'delete': True
+ "r1": {
+ "links": {
+ "r0": {
+ "interface": topo["routers"]["r1"]["links"]["r0"]["interface"],
+ "ospf": {"dead_interval": 65535},
+ "delete": True,
}
}
}
}
result = create_interfaces_cfg(tgen, topo1)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
step(
- "Verify that timer value is deleted from intf & "
- "set to default value 40 sec.")
- input_dict= {
- 'r1': {
- 'links':{
- 'r0': {
- 'ospf':{
- 'timerDeadSecs': 40
- }
- }
- }
- }
- }
- dut = 'r1'
+ "Verify that timer value is deleted from intf & " "set to default value 40 sec."
+ )
+ input_dict = {"r1": {"links": {"r0": {"ospf": {"timerDeadSecs": 40}}}}}
+ dut = "r1"
result = verify_ospf_interface(tgen, topo, dut=dut, input_dict=input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
write_test_footer(tc_name)
diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py
index de11b78824..fdafa50aba 100644
--- a/tests/topotests/rip-topo1/test_rip_topo1.py
+++ b/tests/topotests/rip-topo1/test_rip_topo1.py
@@ -352,9 +352,11 @@ def test_zebra_ipv4_routingTable():
else:
print("r%s ok" % i)
- assert failures == 0, (
- "Zebra IPv4 Routing Table verification failed for router r%s:\n%s"
- % (i, diff)
+ assert (
+ failures == 0
+ ), "Zebra IPv4 Routing Table verification failed for router r%s:\n%s" % (
+ i,
+ diff,
)
# Make sure that all daemons are still running
diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py
index 2976cdefe4..4702d33dae 100644
--- a/tests/topotests/ripng-topo1/test_ripng_topo1.py
+++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py
@@ -373,9 +373,11 @@ def test_zebra_ipv6_routingTable():
else:
print("r%s ok" % i)
- assert failures == 0, (
- "Zebra IPv6 Routing Table verification failed for router r%s:\n%s"
- % (i, diff)
+ assert (
+ failures == 0
+ ), "Zebra IPv6 Routing Table verification failed for router r%s:\n%s" % (
+ i,
+ diff,
)
# Make sure that all daemons are running
diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json
new file mode 100644
index 0000000000..7099043adc
--- /dev/null
+++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo1_ebgp.json
@@ -0,0 +1,157 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json
new file mode 100644
index 0000000000..91820b0491
--- /dev/null
+++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo2_ebgp.json
@@ -0,0 +1,363 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link4": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link5": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link6": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link7": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ },
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link4": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link5": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link6": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link7": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ },
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link4": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link5": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link6": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link7": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link4": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link5": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link6": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link7": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json b/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json
new file mode 100644
index 0000000000..bb72578ff3
--- /dev/null
+++ b/tests/topotests/static_routing_with_ebgp/static_routes_topo4_ebgp.json
@@ -0,0 +1,428 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link0": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link1": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link2": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link3": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link0": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link1": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link2": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link3": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "password": "r1"
+ },
+ "r2-link1": {
+ "password": "r1"
+ },
+ "r2-link2": {
+ "password": "r1"
+ },
+ "r2-link3": {
+ "password": "r1"
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "password": "r1"
+ },
+ "r2-link1": {
+ "password": "r1"
+ },
+ "r2-link2": {
+ "password": "r1"
+ },
+ "r2-link3": {
+ "password": "r1"
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "password": "r1"
+ },
+ "r2-link1": {
+ "password": "r1"
+ },
+ "r2-link2": {
+ "password": "r1"
+ },
+ "r2-link3": {
+ "password": "r1"
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "password": "r1"
+ },
+ "r2-link1": {
+ "password": "r1"
+ },
+ "r2-link2": {
+ "password": "r1"
+ },
+ "r2-link3": {
+ "password": "r1"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link0": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link1": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link2": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link3": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link0": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link1": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link2": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link3": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "vm1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm5": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm6": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py
new file mode 100644
index 0000000000..a33257de65
--- /dev/null
+++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo1_ebgp.py
@@ -0,0 +1,1261 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+
+ -Verify static route ECMP functionality with 2 next hop.
+
+ -Verify static route functionality with 2 next hop and different AD
+ value.
+
+ -Verify RIB status when same route advertise via BGP and static route.
+
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ create_interfaces_cfg,
+ shutdown_bringup_interface,
+ stop_router,
+ start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo1_ebgp.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": ["11.0.20.1/32", "11.0.20.2/32"], "ipv6": ["2::1/128", "2::2/128"]}
+NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"}
+
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+
+
+class CreateTopo(Topo):
+ """
+ Test CreateTopo - topology 1.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment.
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('These tests will not run. (have kernel "{}", '
+ 'requires kernel >= 4.19)'.format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Checking BGP convergence
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether BGP is converged
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def populate_nh():
+ NEXT_HOP_IP = {
+ "nh1": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+ },
+ "nh2": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+ },
+ }
+ return NEXT_HOP_IP
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_static_route_2nh_p0_tc_1_ebgp(request):
+ """
+ Verify static route ECMP functionality with 2 next hop.
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+
+ step(
+ "Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
+ "(28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present on"
+ "R1"
+ )
+ step("ex :- ip route 10.1.1.1/24 28.1.1.2 & ip route 10.1.1.1/24 29.1.1.1")
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ },
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ },
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, static route installed in RIB using show ip route"
+ " with 2 ECMP next hop "
+ )
+ nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert (
+ result is True
+ ), "Testcase {} : Failed" "Error: Routes is missing in RIB".format(tc_name)
+
+ step("Configure IBGP IPv4 peering between R2 and R3 router.")
+ step("Configure redistribute static in BGP on R2 router")
+
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the static route configured with nexthop N1 from running config")
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, after removing the static route with N1 , "
+ "route become active with nexthop N2 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed" "Error: Routes is still present in RIB".format(
+ tc_name
+ )
+
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1")
+
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the static route configured with nexthop N2 from" "running config")
+
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, after removing the static route with N2 , "
+ "route become active with nexthop N1 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N2")
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Shut nexthop interface N1")
+ intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("Only one the nexthops should be active in RIB.")
+
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ protocol=protocol,
+ next_hop=nh,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ dut = "r2"
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ dut = "r2"
+ step("No shut the nexthop interface N1")
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "after shut of nexthop N1 , route become active "
+ "with nexthop N2 and vice versa."
+ )
+ nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Shut nexthop interface N2")
+ intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+ dut = "r2"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ " after shut of nexthop N1 , route become active with "
+ "nexthop N2 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ step("No shut nexthop interface N2")
+ dut = "r2"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "after shut of nexthop N1 , route become active "
+ "with nexthop N2 and vice versa."
+ )
+ nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ dut = "r2"
+ step(
+ "After reload of FRR router , static route installed"
+ " in RIB and FIB properly ."
+ )
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_2nh_admin_dist_p0_tc_2_ebgp(request):
+ """
+ Verify static route functionality with 2 next hop & different AD value.
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+ step(
+ "Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
+ "(28.1.1.2 ) AD 10 and N2 (29.1.1.2) AD 20 , Static route next-hop"
+ "present on R1 \n ex :- ip route 10.1.1.1/24 28.1.1.2 10 & "
+ "ip route 10.1.1.1/24 29.1.1.2 20"
+ )
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ },
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ },
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 2 next hop , lowest AD nexthop is active "
+ )
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ step("Configure IBGP IPv4 peering between R2 and R3 router.")
+ step("Explicit route is added in R3 for R2 nexthop rechability")
+ rt3_rtes = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": NEXT_HOP_IP["nh1"][addr_type] + "/32",
+ "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type],
+ },
+ {
+ "network": NEXT_HOP_IP["nh2"][addr_type] + "/32",
+ "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type],
+ },
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rt3_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Configure redistribute static in BGP on R2 router")
+
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the static route configured with nexthop N1 from" "running config")
+ rt1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rt1_nh1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, after removing the static route with N1 , "
+ "route become active with nexthop N2 and vice versa."
+ )
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte1_nh1,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1")
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rte1_nh1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the static route configured with nexthop N2 from" "running config")
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rte2_nh2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, after removing the static route with N2 , "
+ "route become active with nexthop N1 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N2")
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rte2_nh2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Shut nexthop interface N1")
+ intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("after shut of nexthop N1 , route become active with nexthop N2")
+
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte1_nh1,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("No shut the nexthop interface N1")
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "after shut of nexthop N1 , route become active "
+ "with nexthop N2 and vice versa."
+ )
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Shut nexthop interface N2")
+ intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ " after shut of nexthop N1 , route become active with "
+ "nexthop N2 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("No shut nexthop interface N2")
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "after shut of nexthop N1 , route become active "
+ "with nexthop N2 and vice versa."
+ )
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ dut = "r3"
+ protocol = "bgp"
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ dut = "r2"
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ step(
+ "After reload of FRR router , static route installed"
+ " in RIB and FIB properly ."
+ )
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_bgp_rib(tgen, addr_type, dut, rte1_nh1, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_bgp_rib(tgen, addr_type, dut, rte2_nh2, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_same_rte_from_bgp_static_p0_tc5_ebgp(request):
+ """
+ Verify RIB status when same route advertise via BGP and static
+ route
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+
+ NEXT_HOP_IP = populate_nh()
+ step("Configure EBGP IPv4 peering between R2 and R3 router.")
+
+ step(
+ "Configure IPv4 static route (10.1.1.1/24) in R2 with next hop"
+ "N1 (28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present"
+ "on R1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ },
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ },
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure redistribute static in BGP.")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify on R3 , route receive on R3 BGP table ")
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ step("Verify route installed in the RIB and FIB of R3")
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ step(
+ "Configure 2 links/interfaces between R1 and R3 , keep one"
+ "interface in shut (active) state and other interface in no shut"
+ "(inactive) state"
+ )
+ dut = "r3"
+ intf = topo["routers"]["r3"]["links"]["r1-link0"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ "Configure same static route (10.1.1.1/24) in R3 with inactive"
+ "nexthop interface"
+ )
+
+ step(
+ "Configure same static route 10.1.1.1/24) again in R3 with"
+ "active nexthop interface"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": topo["routers"]["r1"]["links"]["r3-link0"][
+ addr_type
+ ],
+ },
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": topo["routers"]["r1"]["links"]["r3-link1"][
+ addr_type
+ ],
+ },
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify when static route configure with inactive nexthop , "
+ "verify BGP received route is active in the RIB and FIB"
+ )
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in BGP RIB".format(tc_name)
+
+ protocol = "bgp"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in RIB".format(tc_name)
+
+ step("Remove the static route on R3 configured with active" "interface")
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": topo["routers"]["r1"]["links"]["r3-link0"][
+ addr_type
+ ],
+ "delete": True,
+ },
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": topo["routers"]["r1"]["links"]["r3-link1"][
+ addr_type
+ ],
+ "delete": True,
+ },
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step(
+ "After removing the static route with active nexthop verify "
+ "BGP received route is became active in RIB and FIB"
+ )
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in BGP RIB".format(tc_name)
+
+ protocol = "bgp"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py
new file mode 100644
index 0000000000..93320df327
--- /dev/null
+++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py
@@ -0,0 +1,1711 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+ -Verify static route functionality with 8 next hop different AD value
+ and BGP ECMP
+
+ -Verify 8 static route functionality with 8 next hop different AD
+
+ -Verify static route with 8 next hop with different AD value and 8
+ EBGP neighbors
+
+ -Verify static route with 8 next hop with different AD value and 8
+ IBGP neighbors
+
+ -Delete the static route and verify the RIB and FIB state
+
+ -Verify 8 static route functionality with 8 ECMP next hop
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+import random
+from lib.topotest import version_cmp
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ shutdown_bringup_interface,
+ stop_router,
+ start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo2_ebgp.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ "11.0.20.6/32",
+ "11.0.20.7/32",
+ "11.0.20.8/32",
+ ],
+ "ipv6": [
+ "2::1/128",
+ "2::2/128",
+ "2::3/128",
+ "2::4/128",
+ "2::5/128",
+ "2::6/128",
+ "2::7/128",
+ "2::8/128",
+ ],
+}
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+PREFIX2 = {"ipv4": "110.0.20.2/32", "ipv6": "20::2/128"}
+NEXT_HOP_IP = []
+topo_diag = """
+ Please view in a fixed-width font such as Courier.
+ +------+ +------+ +------+
+ | +--------------+ +--------------+ |
+ | | | | | |
+ | R1 +---8 links----+ R2 +---8 links----+ R3 |
+ | | | | | |
+ | +--------------+ +--------------+ |
+ +------+ +------+ +------+
+
+"""
+
+
+class CreateTopo(Topo):
+ """
+ Test CreateTopo - topology 1.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+
+ Set up the pytest environment.
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('These tests will not run. (have kernel "{}", '
+ 'requires kernel >= 4.19)'.format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Checking BGP convergence
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether BGP is converged
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def populate_nh():
+ NEXT_HOP_IP = {
+ "nh1": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+ },
+ "nh2": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+ },
+ "nh3": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0],
+ },
+ "nh4": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0],
+ },
+ "nh5": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0],
+ },
+ "nh6": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0],
+ },
+ "nh7": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0],
+ },
+ "nh8": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0],
+ },
+ }
+ return NEXT_HOP_IP
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_static_rte_with_8ecmp_nh_p1_tc9_ebgp(request):
+ """
+ Verify 8 static route functionality with 8 ECMP next hop
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ NEXT_HOP_IP = populate_nh()
+ step("Configure 8 interfaces / links between R1 and R2")
+ step("Configure 8 interfaces / links between R2 and R3")
+ step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure 8 IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) , N2(22.1.1.2) , N3(23.1.1.2) , N4(24.1.1.2) ,"
+ "N5(25.1.1.2) , N6(26.1.1.2) , N7(27.1.1.2) , N8(28.1.1.2) ,"
+ "Static route next-hop present on R1"
+ )
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+ nh_all[addr_type] = [
+ NEXT_HOP_IP["nh1"][addr_type],
+ NEXT_HOP_IP["nh2"][addr_type],
+ NEXT_HOP_IP["nh3"][addr_type],
+ NEXT_HOP_IP["nh4"][addr_type],
+ NEXT_HOP_IP["nh5"][addr_type],
+ NEXT_HOP_IP["nh6"][addr_type],
+ NEXT_HOP_IP["nh7"][addr_type],
+ NEXT_HOP_IP["nh8"][addr_type],
+ ]
+
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+ dut = "r2"
+ protocol = "static"
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "verify that entry is removed from RIB and FIB of R3 "
+ )
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "verify that entry is removed from RIB and FIB of R3 "
+ )
+ nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed\nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by one")
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed\nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ protocol = "static"
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ # Shutdown interface
+ dut = "r2"
+ step(
+ " interface which is about to be shut no shut between r1 and r2 is " "%s",
+ topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"],
+ )
+ intf = topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("Random no shut of the nexthop interfaces")
+ # Bringup interface
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "After random shut/no shut of nexthop , only that "
+ "nexthop deleted/added from all the routes , other nexthop remain "
+ "unchanged"
+ )
+ dut = "r2"
+ protocol = "static"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Remove random static route with all the nexthop")
+ dut = "r2"
+ randnum = random.randint(1, 7)
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After delete of random route , that route only got deleted from"
+ " RIB/FIB other route are showing properly"
+ )
+ nh = NEXT_HOP_IP["nh{}".format(randnum)][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+ start_router(tgen, "r2")
+
+ step(
+ "After reload of FRR router , static route "
+ "installed in RIB and FIB properly ."
+ )
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ nhp = 1
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Verifying %s routes on r2", addr_type)
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Remove the redistribute static knob")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static", "delete": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the BGP neighbor or redistribute static knob , "
+ "verify route got clear from RIB and FIB of R3 routes "
+ )
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ebgp(request):
+ """
+ Verify static route functionality with 8 next hop different AD
+ value and BGP ECMP
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure 8 interfaces / links between R1 and R2 ,")
+ step("Configure 8 interlaces/links between R2 and R3")
+ step(
+ "Configure IBGP IPv4 peering over loopback interface between"
+ "R2 and R3 router."
+ )
+ step("Configure redistribute static in BGP on R2 router")
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+ "present on R1"
+ )
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop , lowest AD nexthop is active"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ wait=2,
+ attempts=3,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "route become active with next preferred nexthop and nexthop which "
+ "got removed is not shown in RIB and FIB"
+ )
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by one")
+
+ for addr_type in ADDR_TYPES:
+ # add static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ " After configuring them, route is always active with lowest AD"
+ " value and all the nexthop populated in RIB and FIB again"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ wait=2,
+ attempts=3,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ input_dict_5 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_5,
+ next_hop=nhip,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+
+ step("Random no shut of the nexthop interfaces")
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ dut = "r2"
+ protocol = "static"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+ protocol = "bgp"
+ dut = "r3"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, (
+ "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+ )
+
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_ebgp_ecmp_p1_tc8_ebgp(request):
+ """
+ Verify static route with 8 next hop with different AD value and 8
+ EBGP neighbors
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure 8 interfaces / links between R1 and R2")
+ step("Configure 8 interlaces/links between R2 and R3")
+ step("Configure 8 EBGP IPv4 peering between R2 and R3")
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+ "present on R1"
+ )
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop , lowest AD nexthop is active"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "route become active with next preferred nexthop and nexthop which "
+ "got removed is not shown in RIB and FIB"
+ )
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by one")
+
+ for addr_type in ADDR_TYPES:
+ # add static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ " After configuring them, route is always active with lowest AD"
+ " value and all the nexthop populated in RIB and FIB again"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ input_dict_5 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_5,
+ next_hop=nhip,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+
+ step("Random no shut of the nexthop interfaces")
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ dut = "r2"
+ protocol = "static"
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, (
+ "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ebgp(request):
+ """
+ Verify 8 static route functionality with 8 next hop different AD'
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ NEXT_HOP_IP = populate_nh()
+
+ step("Configure 8 interfaces / links between R1 and R2 ")
+ step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80"
+ )
+ step(
+ "Configure nexthop AD in such way for static route S1 , N1 is"
+ "preferred and for S2 , N2 is preferred and so on .."
+ )
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ second_rte = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, second_rte)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop , lowest AD nexthop is active"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Verify that highest AD nexthop are inactive")
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ wait=2,
+ attempts=3,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "route become active with next preferred nexthop and nexthop which"
+ "got removed is not shown in RIB and FIB"
+ )
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by one")
+ for addr_type in ADDR_TYPES:
+ # add static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ " After configuring them, route is always active with lowest AD"
+ " value and all the nexthop populated in RIB and FIB again"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}}
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Route with "
+ "lowest AD is missing in RIB".format(tc_name)
+
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ input_dict_5 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_5,
+ next_hop=nhip,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+
+ step("Random no shut of the nexthop interfaces")
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ step("Remove random static route with all the nexthop")
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "route become active with next preferred nexthop and nexthop "
+ "which got removed is not shown in RIB and FIB"
+ )
+ nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route "
+ " is still present in RIB".format(tc_name)
+
+ step("Reconfigure the deleted routes and verify they are installed")
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \nError: Route "
+ " is still present in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ step("After reloading, verify that routes are still present in R2.")
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ second_rte,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ )
+ assert result is True, (
+ "Testcase {} : Failed \nError: Route "
+ " is missing in RIB".format(tc_name)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_delete_p0_tc11_ebgp(request):
+ """
+ Delete the static route and verify the RIB and FIB state
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ NEXT_HOP_IP = populate_nh()
+
+ step("Configure 8 interfaces / links between R1 and R2 ")
+ step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80"
+ )
+ step(
+ "Configure nexthop AD in such way for static route S1 , N1 is"
+ "preferred and for S2 , N2 is preferred and so on .."
+ )
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ second_rte = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, second_rte)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop , lowest AD nexthop is active"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Verify that highest AD nexthop are inactive")
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the redistribute static knob")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static", "delete": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify after removing the redistribute static from BGP all the"
+ "routes got delete from RIB and FIB of R3 "
+ )
+
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ second_rte = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, second_rte)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ " After removing all the routes and nexthop from R2 , "
+ " verify R2 RIB and FIB is cleared"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still active in RIB".format(tc_name)
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py
new file mode 100644
index 0000000000..75657a8895
--- /dev/null
+++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py
@@ -0,0 +1,994 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+
+Following tests are covered in the script.
+
+- Verify static route are blocked from route-map and prefix-list
+ applied in BGP nbrs
+- Verify Static route when FRR connected to 2 TOR
+"""
+
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+import ipaddress
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ check_address_types,
+ step,
+ create_prefix_lists,
+ create_route_maps,
+ create_interfaces_cfg,
+ verify_prefix_lists,
+ verify_route_maps,
+)
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ clear_bgp_and_verify,
+ clear_bgp,
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo4_ebgp.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": "2.2.2.2/32", "ipv6": "22:22::2/128"}
+NEXT_HOP_IP = {}
+
+
+class CreateTopo(Topo):
+ """
+ Test CreateTopo - topology 1.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Set up the pytest environment.
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('These tests will not run. (have kernel "{}", '
+ 'requires kernel >= 4.19)'.format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Checking BGP convergence
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether BGP is converged
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Tests starting
+#
+#####################################################
+def static_routes_rmap_pfxlist_p0_tc7_ebgp(request):
+ """
+ Verify static route are blocked from route-map & prefix-list applied in BGP
+ nbrs
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ reset_config_on_routers(tgen)
+ step("Configure holddown timer = 1 keep alive = 3 in all the neighbors")
+ step("verify bgp convergence before starting test case")
+
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, bgp_convergence
+ )
+
+ step(
+ "Configure 4 IPv4 and 4 IPv6 nbrs with password with mismatch "
+ " authentication between FRR routers "
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Api call to modfiy BGP timerse
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {"password": "r2"},
+ "r2-link1": {"password": "r2"},
+ "r2-link2": {"password": "r2"},
+ "r2-link3": {"password": "r2"},
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link0": {"password": "r2"},
+ "r2-link1": {"password": "r2"},
+ "r2-link2": {"password": "r2"},
+ "r2-link3": {"password": "r2"},
+ }
+ },
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+ clear_bgp(tgen, addr_type, "r2")
+
+ step(" All BGP nbrs are down as authentication is mismatch on both" " the sides")
+
+ bgp_convergence = verify_bgp_convergence(tgen, topo, expected=False)
+ assert bgp_convergence is not True, "Testcase {} : "
+ "Failed \n BGP nbrs must be down. Error: {}".format(tc_name, bgp_convergence)
+
+ step(
+ "Configure 4 IPv4 and 4 IPv6 nbrs with macthing password "
+ " authentication between FRR routers "
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {"password": "r1"},
+ "r2-link1": {"password": "r1"},
+ "r2-link2": {"password": "r1"},
+ "r2-link3": {"password": "r1"},
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link0": {"password": "r1"},
+ "r2-link1": {"password": "r1"},
+ "r2-link2": {"password": "r1"},
+ "r2-link3": {"password": "r1"},
+ }
+ },
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, deepcopy(input_dict))
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("All BGP nbrs are up as authentication is matched now")
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, "Testcase {} : Failed \n " "Error: {}".format(
+ tc_name, bgp_convergence
+ )
+
+ step("Create prefix list P1 to permit VM3 & deny VM1 v4 & v6 routes")
+ step("Create prefix list P2 to permit VM6 IPv4 and IPv6 routes")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "prefix_lists": {
+ addr_type: {
+ "pf_list_1_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": topo["routers"]["r2"]["links"]["vm3"][
+ addr_type
+ ],
+ "action": "permit",
+ },
+ {
+ "seqid": 20,
+ "network": topo["routers"]["r2"]["links"]["vm1"][
+ addr_type
+ ],
+ "action": "deny",
+ },
+ ],
+ "pf_list_2_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": topo["routers"]["r2"]["links"]["vm6"][
+ addr_type
+ ],
+ "action": "permit",
+ }
+ ],
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Prefix list created with matching networks deny or permit "
+ "show ip prefix list"
+ )
+ result = verify_prefix_lists(tgen, input_dict_2)
+ assert result is not True, "Testcase {} : Failed \n"
+ " Error: {}".format(tc_name, result)
+
+ step("Redistribute all the routes (connected, static)")
+ input_dict_2_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2_r2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2_r3 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute connected in Router BGP")
+
+ input_dict_2_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2_r3 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply prefix list P1 on BGP neighbors 1 2 3 4 connected from " "frr r1")
+ # Configure prefix list to bgp neighbor
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link1": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link2": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link3": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply prefix list P2 on BGP nbrs 5 & 6 connected from FRR-2")
+ # Configure prefix list to bgp neighbor
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link1": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link2": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link3": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ clear_bgp_and_verify(tgen, topo, "r2")
+
+ step(
+ "VM1 IPv4 and IPv6 Route which is denied using prefix list is "
+ "not present on FRR1 side routing table , also not able to "
+ "ping the routes show ip route"
+ )
+
+ dut = "r1"
+ protocol = "bgp"
+ ntwk_r2_vm1 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type])
+ ).network
+ )
+ input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+ result4 = verify_rib(
+ tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
+ )
+ assert result4 is not True, "Testcase {} : Failed , VM1 route is "
+ "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+ step(
+ "VM4 and VM6 IPV4 and IPv6 address are present in local and "
+ "FRR2 routing table show ip bgp show ip route"
+ )
+
+ dut = "r2"
+ ntwk_r2_vm6 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type])
+ ).network
+ )
+ input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}}
+ result4 = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result4 is True, "Testcase {} : Failed.\n Error: {}".format(
+ tc_name, result4
+ )
+
+ step("Remove prefix list from all the neighbors")
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link1": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link2": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link3": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link1": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link2": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link3": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ clear_bgp_and_verify(tgen, topo, "r2")
+
+ step("Create RouteMap_1 with prefix list P1 and weight 50")
+ # Create route map
+ rmap_dict = {
+ "r2": {
+ "route_maps": {
+ "rmap_pf_list_1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {"weight": 50},
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, rmap_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create RouteMap_2 with prefix list P2 and weight 50")
+ # Create route map
+ rmap_dict = {
+ "r2": {
+ "route_maps": {
+ "rmap_pf_list_2_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {"weight": 50},
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_2_{}".format(addr_type)
+ }
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, rmap_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify Route-map created verify using show route-map")
+ # verify rmap_pf_list_1 and rmap_pf_list_2 are present in router r2
+ input_dict = {
+ "r2": {
+ "route_maps": [
+ "rmap_pf_list_1_{}".format(addr_type),
+ "rmap_pf_list_2_{}".format(addr_type),
+ ]
+ }
+ }
+ result = verify_route_maps(tgen, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply policy RouteMap_1 nbrs 1 2 3 4 to FRR 1")
+ # Configure prefix list to bgp neighbor
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_1_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_1_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_1_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_1_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply policy RouteMap_2 nbrs 5 and 6 to FRR2")
+ # Configure prefix list to bgp neighbor
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_2_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_2_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_2_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_2_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After applying to BGP neighbors verify VM1 IPv4 and IPv6 Route"
+ " which is denied using prefix list is not present on FRR side"
+ " routing table , also not able to ping the routes show ip route"
+ " and VM4 and VM6 IPV4 and IPv6 address are present in local and"
+ " FRR routing table show ip bgp show ip route"
+ )
+
+ dut = "r1"
+ protocol = "bgp"
+ ntwk_r2_vm1 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type])
+ ).network
+ )
+ input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+ result4 = verify_rib(
+ tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
+ )
+ assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format(
+ tc_name, result4
+ )
+
+ step("vm4 should be present in FRR1")
+ dut = "r1"
+ ntwk_r2_vm1 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type])
+ ).network
+ )
+ input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+ result4 = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result4 is True, "Testcase {} : Failed , VM1 route is "
+ "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+ step("vm4 should be present in FRR2")
+ dut = "r2"
+ ntwk_r2_vm1 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type])
+ ).network
+ )
+ input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+ result4 = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result4 is True, "Testcase {} : Failed , VM1 route is "
+ "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+ dut = "r3"
+ protocol = "bgp"
+ ntwk_r2_vm6 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type])
+ ).network
+ )
+ input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}}
+ result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result4 is True, "Testcase {} : Failed.\n Error: {}".format(
+ tc_name, result4
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json
new file mode 100644
index 0000000000..99b197366a
--- /dev/null
+++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo1_ibgp.json
@@ -0,0 +1,157 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json
new file mode 100644
index 0000000000..47596a0a1a
--- /dev/null
+++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo2_ibgp.json
@@ -0,0 +1,371 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+
+
+ "dest_link": {
+ "r2-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link4": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link5": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link6": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link7": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ },
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+
+
+ "dest_link": {
+ "r2-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link4": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link5": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link6": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r2-link7": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ },
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+
+
+ "dest_link": {
+ "r3-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link4": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link5": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link6": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link7": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+
+
+ "dest_link": {
+ "r3-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link2": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link3": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link4": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link5": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link6": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ },
+ "r3-link7": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json
new file mode 100644
index 0000000000..4e27229f34
--- /dev/null
+++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo3_ibgp.json
@@ -0,0 +1,189 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 29,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link0": {
+ "keepalivetimer": 1,
+ "holddowntimer": 4
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json b/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json
new file mode 100644
index 0000000000..bb72578ff3
--- /dev/null
+++ b/tests/topotests/static_routing_with_ibgp/static_routes_topo4_ibgp.json
@@ -0,0 +1,428 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link0": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link1": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link2": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link3": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link0": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link1": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link2": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r1-link3": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r1-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "password": "r1"
+ },
+ "r2-link1": {
+ "password": "r1"
+ },
+ "r2-link2": {
+ "password": "r1"
+ },
+ "r2-link3": {
+ "password": "r1"
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "password": "r1"
+ },
+ "r2-link1": {
+ "password": "r1"
+ },
+ "r2-link2": {
+ "password": "r1"
+ },
+ "r2-link3": {
+ "password": "r1"
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "password": "r1"
+ },
+ "r2-link1": {
+ "password": "r1"
+ },
+ "r2-link2": {
+ "password": "r1"
+ },
+ "r2-link3": {
+ "password": "r1"
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "password": "r1"
+ },
+ "r2-link1": {
+ "password": "r1"
+ },
+ "r2-link2": {
+ "password": "r1"
+ },
+ "r2-link3": {
+ "password": "r1"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link0": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r2-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "vm5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link0": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link1": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link2": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link3": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link0": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link1": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link2": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ },
+ "r3-link3": {
+ "password": "r1",
+ "holddowntimer": 3,
+ "keepalivetimer": 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "vm1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm5": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ },
+ "vm6": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py
new file mode 100644
index 0000000000..130f4fd9aa
--- /dev/null
+++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py
@@ -0,0 +1,1083 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+
+ -Verify static route ECMP functionality with 2 next hop
+
+ -Verify static route functionality with 2 next hop and different AD
+ value
+
+ -Verify RIB status when same route advertise via BGP and static route
+
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ create_interfaces_cfg,
+ shutdown_bringup_interface,
+ stop_router,
+ start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo1_ibgp.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": ["11.0.20.1/32", "11.0.20.2/32"], "ipv6": ["2::1/128", "2::2/128"]}
+NETWORK2 = {"ipv4": "11.0.20.1/32", "ipv6": "2::1/128"}
+
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+
+
+class CreateTopo(Topo):
+ """
+ Test CreateTopo - topology 1.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+
+ Set up the pytest environment.
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('These tests will not run. (have kernel "{}", '
+ 'requires kernel >= 4.19)'.format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Checking BGP convergence
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether BGP is converged
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def populate_nh():
+ NEXT_HOP_IP = {
+ "nh1": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+ },
+ "nh2": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+ },
+ }
+ return NEXT_HOP_IP
+
+
+#####################################################
+#
+# Tests starting
+#
+#####################################################
+
+
+def test_static_route_2nh_p0_tc_1_ibgp(request):
+ """
+ Verify static route ECMP functionality with 2 next hop
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+
+ step(
+ "Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
+ "(28.1.1.2 ) and N2 (29.1.1.2) , Static route next-hop present on"
+ "R1"
+ )
+ step("ex :- ip route 10.1.1.1/24 28.1.1.2 & ip route 10.1.1.1/24 29.1.1.1")
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ },
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ },
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, static route installed in RIB using show ip route"
+ " with 2 ECMP next hop "
+ )
+ nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Configure IBGP IPv4 peering between R2 and R3 router.")
+ step("Configure redistribute static in BGP on R2 router")
+
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the static route configured with nexthop N1 from running config")
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, after removing the static route with N1 , "
+ "route become active with nexthop N2 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1")
+
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the static route configured with nexthop N2 from running config")
+
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, after removing the static route with N2 , "
+ "route become active with nexthop N1 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N2")
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Shut nexthop interface N1")
+ intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("Only one the nexthops should be active in RIB.")
+
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ protocol=protocol,
+ next_hop=nh,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ dut = "r2"
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ dut = "r2"
+ step("No shut the nexthop interface N1")
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "after shut of nexthop N1 , route become active "
+ "with nexthop N2 and vice versa."
+ )
+ nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Shut nexthop interface N2")
+ intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+ dut = "r2"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ " after shut of nexthop N1 , route become active with "
+ "nexthop N2 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ step("No shut nexthop interface N2")
+ dut = "r2"
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "after shut of nexthop N1 , route become active "
+ "with nexthop N2 and vice versa."
+ )
+ nh = [NEXT_HOP_IP["nh1"][addr_type], NEXT_HOP_IP["nh2"][addr_type]]
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " missing in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ dut = "r2"
+ step(
+ "After reload of FRR router , static route installed"
+ " in RIB and FIB properly ."
+ )
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route is"
+ " still present in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_2nh_admin_dist_p0_tc_2_ibgp(request):
+ """
+ Verify static route functionality with 2 next hop & different AD value
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+ step(
+ "Configure IPv4 static route (10.1.1.1) in R2 with next hop N1"
+ "(28.1.1.2 ) AD 10 and N2 (29.1.1.2) AD 20 , Static route next-hop"
+ "present on R1 \n ex :- ip route 10.1.1.1/24 28.1.1.2 10 & "
+ "ip route 10.1.1.1/24 29.1.1.2 20"
+ )
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ },
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ },
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 2 next hop , lowest AD nexthop is active "
+ )
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ step("Configure IBGP IPv4 peering between R2 and R3 router.")
+ step("Explicit route is added in R3 for R2 nexthop rechability")
+ rt3_rtes = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": NEXT_HOP_IP["nh1"][addr_type] + "/32",
+ "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type],
+ },
+ {
+ "network": NEXT_HOP_IP["nh2"][addr_type] + "/32",
+ "next_hop": topo["routers"]["r2"]["links"]["r3"][addr_type],
+ },
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rt3_rtes)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Configure redistribute static in BGP on R2 router")
+
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the static route configured with nexthop N1 from running config")
+ rt1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rt1_nh1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, after removing the static route with N1 , "
+ "route become active with nexthop N2 and vice versa."
+ )
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte1_nh1,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1")
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rte1_nh1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the static route configured with nexthop N2 from running config")
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rte2_nh2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On R2, after removing the static route with N2 , "
+ "route become active with nexthop N1 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N2")
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, rte2_nh2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Shut nexthop interface N1")
+ intf = topo["routers"]["r2"]["links"]["r1-link0"]["interface"]
+
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("after shut of nexthop N1 , route become active with nexthop N2")
+
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte1_nh1,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, rte2_nh2, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("No shut the nexthop interface N1")
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "after shut of nexthop N1 , route become active "
+ "with nexthop N2 and vice versa."
+ )
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("Shut nexthop interface N2")
+ intf = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step(
+ " after shut of nexthop N1 , route become active with "
+ "nexthop N2 and vice versa."
+ )
+ nh = NEXT_HOP_IP["nh2"][addr_type]
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB".format(tc_name)
+
+ step("No shut nexthop interface N2")
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "after shut of nexthop N1 , route become active "
+ "with nexthop N2 and vice versa."
+ )
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ dut = "r3"
+ protocol = "bgp"
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ dut = "r2"
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ step(
+ "After reload of FRR router , static route installed"
+ " in RIB and FIB properly ."
+ )
+ rte1_nh1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh1"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, rte1_nh1, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_bgp_rib(tgen, addr_type, dut, rte1_nh1, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "missing in RIB".format(tc_name)
+
+ rte2_nh2 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh2"][addr_type],
+ "admin_distance": 20,
+ }
+ ]
+ }
+ }
+ nh = [NEXT_HOP_IP["nh2"][addr_type]]
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_bgp_rib(tgen, addr_type, dut, rte2_nh2, next_hop=nh)
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ rte2_nh2,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ "not active in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py
new file mode 100644
index 0000000000..0a757c9f28
--- /dev/null
+++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py
@@ -0,0 +1,1974 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+ -Verify static route functionality with 8 next hop different AD value
+ and BGP ECMP
+
+ -Verify 8 static route functionality with 8 next hop different AD
+
+ -Verify static route with 8 next hop with different AD value and 8
+ EBGP neighbors
+
+ -Verify static route with 8 next hop with different AD value and 8
+ IBGP neighbors
+
+ -Delete the static route and verify the RIB and FIB state
+
+ -Verify 8 static route functionality with 8 ECMP next hop
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+from time import sleep
+import random
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ create_interfaces_cfg,
+ shutdown_bringup_interface,
+ stop_router,
+ start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.topotest import version_cmp
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo2_ibgp.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ "11.0.20.6/32",
+ "11.0.20.7/32",
+ "11.0.20.8/32",
+ ],
+ "ipv6": [
+ "2::1/128",
+ "2::2/128",
+ "2::3/128",
+ "2::4/128",
+ "2::5/128",
+ "2::6/128",
+ "2::7/128",
+ "2::8/128",
+ ],
+}
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+PREFIX2 = {"ipv4": "110.0.20.2/32", "ipv6": "20::2/128"}
+NEXT_HOP_IP = []
+topo_diag = """
+ Please view in a fixed-width font such as Courier.
+ +------+ +------+ +------+
+ | +--------------+ +--------------+ |
+ | | | | | |
+ | R1 +---8 links----+ R2 +---8 links----+ R3 |
+ | | | | | |
+ | +--------------+ +--------------+ |
+ +------+ +------+ +------+
+
+"""
+
+
+class CreateTopo(Topo):
+ """
+ Test CreateTopo - topology 1.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+
+ Set up the pytest environment.
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('These tests will not run. (have kernel "{}", '
+ 'requires kernel >= 4.19)'.format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Checking BGP convergence
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Api call verify whether BGP is converged
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def populate_nh():
+ NEXT_HOP_IP = {
+ "nh1": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+ },
+ "nh2": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+ },
+ "nh3": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0],
+ },
+ "nh4": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0],
+ },
+ "nh5": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0],
+ },
+ "nh6": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0],
+ },
+ "nh7": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0],
+ },
+ "nh8": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0],
+ },
+ }
+ return NEXT_HOP_IP
+
+
+#####################################################
+#
+# Tests starting
+#
+#####################################################
+
+
+def test_static_rte_with_8ecmp_nh_p1_tc9_ibgp(request):
+ """
+ Verify 8 static route functionality with 8 ECMP next hop
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ NEXT_HOP_IP = populate_nh()
+ step("Configure 8 interfaces / links between R1 and R2")
+ step("Configure 8 interfaces / links between R2 and R3")
+ step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure 8 IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) , N2(22.1.1.2) , N3(23.1.1.2) , N4(24.1.1.2) ,"
+ "N5(25.1.1.2) , N6(26.1.1.2) , N7(27.1.1.2) , N8(28.1.1.2) ,"
+ "Static route next-hop present on R1"
+ )
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+ nh_all[addr_type] = [
+ NEXT_HOP_IP["nh1"][addr_type],
+ NEXT_HOP_IP["nh2"][addr_type],
+ NEXT_HOP_IP["nh3"][addr_type],
+ NEXT_HOP_IP["nh4"][addr_type],
+ NEXT_HOP_IP["nh5"][addr_type],
+ NEXT_HOP_IP["nh6"][addr_type],
+ NEXT_HOP_IP["nh7"][addr_type],
+ NEXT_HOP_IP["nh8"][addr_type],
+ ]
+
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+ dut = "r2"
+ protocol = "static"
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "verify that entry is removed from RIB and FIB of R3 "
+ )
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "verify that entry is removed from RIB and FIB of R3 "
+ )
+ nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed\nError: Routes is"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by one")
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed\nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ protocol = "static"
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ # Shutdown interface
+ dut = "r2"
+ step(
+ " interface which is about to be shut no shut between r1 and r2 is " "%s",
+ topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"],
+ )
+ intf = topo["routers"]["r2"]["links"]["r1-link{}".format(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("Random no shut of the nexthop interfaces")
+ # Bringup interface
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step(
+ "After random shut/no shut of nexthop , only that "
+ "nexthop deleted/added from all the routes , other nexthop remain "
+ "unchanged"
+ )
+ dut = "r2"
+ protocol = "static"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Remove random static route with all the nexthop")
+ dut = "r2"
+ randnum = random.randint(1, 7)
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After delete of random route , that route only got deleted from"
+ " RIB/FIB other route are showing properly"
+ )
+ nh = NEXT_HOP_IP["nh{}".format(randnum)][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+ start_router(tgen, "r2")
+
+ step(
+ "After reload of FRR router , static route "
+ "installed in RIB and FIB properly ."
+ )
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ nhp = 1
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Verifying %s routes on r2", addr_type)
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Remove the redistribute static knob")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static", "delete": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the BGP neighbor or redistribute static knob , "
+ "verify route got clear from RIB and FIB of R3 routes "
+ )
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request):
+ """
+ Verify static route functionality with 8 next hop different AD
+ value and BGP ECMP
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure 8 interfaces / links between R1 and R2 ,")
+ step("Configure 8 interlaces/links between R2 and R3")
+ step(
+ "Configure IBGP IPv4 peering over loopback interface between"
+ "R2 and R3 router."
+ )
+ step("Configure redistribute static in BGP on R2 router")
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+ "present on R1"
+ )
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop , lowest AD nexthop is active"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ wait=2,
+ attempts=3,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "route become active with next preferred nexthop and nexthop which "
+ "got removed is not shown in RIB and FIB"
+ )
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by one")
+
+ for addr_type in ADDR_TYPES:
+ # add static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ " After configuring them, route is always active with lowest AD"
+ " value and all the nexthop populated in RIB and FIB again"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ wait=2,
+ attempts=3,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ input_dict_5 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_5,
+ next_hop=nhip,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+
+ step("Random no shut of the nexthop interfaces")
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ protocol = "bgp"
+ # this is next hop reachability route in r3 as we are using ibgp
+ dut = "r3"
+ for addr_type in ADDR_TYPES:
+ nh_as_rte = NEXT_HOP_IP["nh1"][addr_type] + "/32"
+ # add static routes
+ nh_static_rte = {
+ "r3": {"static_routes": [{"network": nh_as_rte, "next_hop": "Null0"}]}
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, nh_static_rte)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After each interface shut and no shut between R2 -R3 ,verify static"
+ "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain"
+ " unchanged"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ protocol = "static"
+ dut = "r2"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+ protocol = "bgp"
+ dut = "r3"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, (
+ "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+ )
+
+ step("BGP neighbor remove and add")
+ for rtr in ["r2", "r3"]:
+ if "bgp" in topo["routers"][rtr].keys():
+ delete_bgp = {rtr: {"bgp": {"delete": True}}}
+ result = create_router_bgp(tgen, topo, delete_bgp)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ create_router_bgp(tgen, topo["routers"])
+
+ NEXT_HOP_IP = populate_nh()
+ step("Verify routes are still present after delete and add bgp")
+ dut = "r2"
+ protocol = "static"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, (
+ "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+ )
+
+ dut = "r3"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, (
+ "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+ )
+
+ step("Remove the redistribute static knob")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static", "delete": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ logger.info("Remove redistribute static")
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("verify that routes are deleted from R3 routing table")
+
+ dut = "r3"
+ protocol = "bgp"
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " strill present in RIB of R3".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_ibgp_ecmp_p1_tc7_ibgp(request):
+ """
+ Verify static route with 8 next hop with different AD value and 8
+ IBGP neighbors
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step("Configure 8 interfaces / links between R1 and R2")
+ step("Configure 8 interlaces/links between R2 and R3")
+ step("Configure 8 IBGP IPv4 peering between R2 and R3")
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+ "present on R1"
+ )
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop , lowest AD nexthop is active"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "route become active with next preferred nexthop and nexthop which "
+ "got removed is not shown in RIB and FIB"
+ )
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by one")
+
+ for addr_type in ADDR_TYPES:
+ # add static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ " After configuring them, route is always active with lowest AD"
+ " value and all the nexthop populated in RIB and FIB again"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ input_dict_5 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_5,
+ next_hop=nhip,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+
+ step("Random no shut of the nexthop interfaces")
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ dut = "r2"
+ protocol = "bgp"
+
+ # this is next hop reachability route in r3 as we are using ibgp
+ dut = "r3"
+ for addr_type in ADDR_TYPES:
+ nh_as_rte = NEXT_HOP_IP["nh1"][addr_type] + "/32"
+ # add static routes
+ nh_static_rte = {
+ "r3": {"static_routes": [{"network": nh_as_rte, "next_hop": "Null0"}]}
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, nh_static_rte)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After each interface shut and no shut between R2 -R3 ,verify static"
+ "route is present in the RIB & FIB of R3 & R2 RIB/FIB is remain"
+ " unchanged"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ protocol = "static"
+ dut = "r2"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+ protocol = "bgp"
+ dut = "r3"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert (
+ result is True
+ ), "Testcase {}: Failed \n " "Error: Routes are missing in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, (
+ "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+ )
+
+ step("BGP neighbor remove and add")
+ for rtr in ["r2", "r3"]:
+ if "bgp" in topo["routers"][rtr].keys():
+ delete_bgp = {rtr: {"bgp": {"delete": True}}}
+ result = create_router_bgp(tgen, topo, delete_bgp)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ create_router_bgp(tgen, topo["routers"])
+
+ NEXT_HOP_IP = populate_nh()
+ step("Verify routes are still present after delete and add bgp")
+ dut = "r2"
+ protocol = "static"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, (
+ "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+ )
+
+ dut = "r3"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, (
+ "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+ )
+
+ step("Remove the redistribute static knob")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static", "delete": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ logger.info("Remove redistribute static")
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("verify that routes are deleted from R3 routing table")
+
+ dut = "r3"
+ protocol = "bgp"
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type]}]}}
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB of R3".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ibgp(request):
+ """
+ Verify 8 static route functionality with 8 next hop different AD'
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ NEXT_HOP_IP = populate_nh()
+
+ step("Configure 8 interfaces / links between R1 and R2 ")
+ step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80"
+ )
+ step(
+ "Configure nexthop AD in such way for static route S1 , N1 is"
+ "preferred and for S2 , N2 is preferred and so on .."
+ )
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ second_rte = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, second_rte)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop , lowest AD nexthop is active"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Verify that highest AD nexthop are inactive")
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ wait=2,
+ attempts=3,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "route become active with next preferred nexthop and nexthop which"
+ "got removed is not shown in RIB and FIB"
+ )
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by one")
+ for addr_type in ADDR_TYPES:
+ # add static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ " After configuring them, route is always active with lowest AD"
+ " value and all the nexthop populated in RIB and FIB again"
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {"r2": {"static_routes": [{"network": PREFIX1[addr_type],}]}}
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Route with "
+ "lowest AD is missing in RIB".format(tc_name)
+
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ input_dict_5 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_5,
+ next_hop=nhip,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+
+ step("Random no shut of the nexthop interfaces")
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ step("Remove random static route with all the nexthop")
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one , "
+ "route become active with next preferred nexthop and nexthop "
+ "which got removed is not shown in RIB and FIB"
+ )
+ nh = NEXT_HOP_IP["nh" + str(nhp)][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Route "
+ " is still present in RIB".format(tc_name)
+
+ step("Reconfigure the deleted routes and verify they are installed")
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, protocol=protocol)
+ assert result is True, "Testcase {} : Failed \nError: Route "
+ " is still present in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+
+ start_router(tgen, "r2")
+
+ step("After reloading, verify that routes are still present in R2.")
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ second_rte,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ )
+ assert result is True, (
+ "Testcase {} : Failed \nError: Route "
+ " is missing in RIB".format(tc_name)
+ )
+
+ step("Remove the redistribute static knob")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static", "delete": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the BGP neighbor or redistribute static knob , "
+ "verify route got clear from RIB and FIB of R3 routes "
+ )
+ dut = "r3"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_static_route_delete_p0_tc11_ibgp(request):
+ """
+ Delete the static route and verify the RIB and FIB state
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ NEXT_HOP_IP = populate_nh()
+
+ step("Configure 8 interfaces / links between R1 and R2 ")
+ step("Configure 8 IBGP IPv4 peering between R2 and R3 router.")
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80"
+ )
+ step(
+ "Configure nexthop AD in such way for static route S1 , N1 is"
+ "preferred and for S2 , N2 is preferred and so on .."
+ )
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ second_rte = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, second_rte)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop , lowest AD nexthop is active"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Verify that highest AD nexthop are inactive")
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " are missing in RIB".format(tc_name)
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Remove the redistribute static knob")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static", "delete": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify after removing the redistribute static from BGP all the"
+ "routes got delete from RIB and FIB of R3 "
+ )
+
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, protocol=protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ second_rte = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX2[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, second_rte)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ " After removing all the routes and nexthop from R2 , "
+ " verify R2 RIB and FIB is cleared"
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still active in RIB".format(tc_name)
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py
new file mode 100644
index 0000000000..924fb3a598
--- /dev/null
+++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py
@@ -0,0 +1,875 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+ -Verify static route ECMP functionality with 8 next hop
+
+ -Verify static route functionality with 8 next hop different AD value
+
+ -Verify static route with tag option
+
+ -Verify BGP did not install the static route when it receive route
+ with local next hop
+
+"""
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+from copy import deepcopy
+import random
+from re import search as re_search
+
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ create_static_routes,
+ check_address_types,
+ step,
+ create_interfaces_cfg,
+ shutdown_bringup_interface,
+ stop_router,
+ start_router,
+)
+from lib.topolog import logger
+from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo3_ibgp.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {
+ "ipv4": [
+ "11.0.20.1/32",
+ "11.0.20.2/32",
+ "11.0.20.3/32",
+ "11.0.20.4/32",
+ "11.0.20.5/32",
+ "11.0.20.6/32",
+ "11.0.20.7/32",
+ "11.0.20.8/32",
+ ],
+ "ipv6": [
+ "2::1/128",
+ "2::2/128",
+ "2::3/128",
+ "2::4/128",
+ "2::5/128",
+ "2::6/128",
+ "2::7/128",
+ "2::8/128",
+ ],
+}
+PREFIX1 = {"ipv4": "110.0.20.1/32", "ipv6": "20::1/128"}
+NETWORK2 = {"ipv4": ["11.0.20.1/32"], "ipv6": ["2::1/128"]}
+NEXT_HOP_IP = []
+
+
+class CreateTopo(Topo):
+ """
+ Test CreateTopo - topology 1.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+
+ Set up the pytest environment.
+
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('These tests will not run. (have kernel "{}", '
+ 'requires kernel >= 4.19)'.format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Checking BGP convergence
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether BGP is converged
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def populate_nh():
+ NEXT_HOP_IP = {
+ "nh1": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link0"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link0"]["ipv6"].split("/")[0],
+ },
+ "nh2": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0],
+ },
+ "nh3": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0],
+ },
+ "nh4": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link3"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link3"]["ipv6"].split("/")[0],
+ },
+ "nh5": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link4"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link4"]["ipv6"].split("/")[0],
+ },
+ "nh6": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link5"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link5"]["ipv6"].split("/")[0],
+ },
+ "nh7": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link6"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link6"]["ipv6"].split("/")[0],
+ },
+ "nh8": {
+ "ipv4": topo["routers"]["r1"]["links"]["r2-link7"]["ipv4"].split("/")[0],
+ "ipv6": topo["routers"]["r1"]["links"]["r2-link7"]["ipv6"].split("/")[0],
+ },
+ }
+ return NEXT_HOP_IP
+
+
+#####################################################
+#
+# Tests starting
+#
+#####################################################
+
+
+def test_staticroute_with_ecmp_p0_tc3_ibgp(request):
+ """
+ Verify static route ECMP functionality with 8 next hop'
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+
+ step("Configure 8 interfaces / links between R1 and R2,")
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2), N2(22.1.1.2), N3(23.1.1.2), N4(24.1.1.2),"
+ "N5(25.1.1.2), N6(26.1.1.2), N7(27.1.1.2),N8(28.1.1.2), Static"
+ "route next-hop present on R1"
+ )
+
+ step("Configure IBGP IPv4 peering between R2 and R3 router.")
+
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+ nh = [
+ NEXT_HOP_IP["nh1"][addr_type],
+ NEXT_HOP_IP["nh2"][addr_type],
+ NEXT_HOP_IP["nh3"][addr_type],
+ NEXT_HOP_IP["nh4"][addr_type],
+ NEXT_HOP_IP["nh5"][addr_type],
+ NEXT_HOP_IP["nh6"][addr_type],
+ NEXT_HOP_IP["nh7"][addr_type],
+ NEXT_HOP_IP["nh8"][addr_type],
+ ]
+
+ dut = "r2"
+ protocol = "static"
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by" "one")
+
+ for addr_type in ADDR_TYPES:
+ # add static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ input_dict_5 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_5,
+ next_hop=nhip,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+
+ step("Random no shut of the nexthop interfaces")
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+ start_router(tgen, "r2")
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \nError: Routes are"
+ " missing in RIB".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_staticroute_with_ecmp_with_diff_AD_p0_tc4_ibgp(request):
+ """
+ Verify static route ECMP functionality with 8 next hop
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+
+ step("Configure 8 interfaces / links between R1 and R2,")
+ step("Configure IBGP IPv4 peering between R2 and R3 router.")
+ reset_config_on_routers(tgen)
+ NEXT_HOP_IP = populate_nh()
+ nh_all = {}
+ for addr_type in ADDR_TYPES:
+ nh_all[addr_type] = []
+ for nhp in range(1, 9):
+ nh_all[addr_type].append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ step(
+ "Configure IPv4 static route in R2 with 8 next hop"
+ "N1(21.1.1.2) AD 10, N2(22.1.1.2) AD 20, N3(23.1.1.2) AD 30,"
+ "N4(24.1.1.2) AD 40, N5(25.1.1.2) AD 50, N6(26.1.1.2) AD 60,"
+ "N7(27.1.1.2) AD 70, N8(28.1.1.2) AD 80, Static route next-hop"
+ "present on R1"
+ )
+ for addr_type in ADDR_TYPES:
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ logger.info("Verifying %s routes on r2", addr_type)
+
+ step(
+ "On R2, static route installed in RIB using "
+ "show ip route with 8 next hop, lowest AD nexthop is active"
+ )
+ step("On R2, static route with lowest AD nexthop installed in FIB")
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Route with "
+ " lowest AD is missing in RIB".format(tc_name)
+
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " with high AD are active in RIB".format(tc_name)
+
+ step("Configure redistribute static in BGP on R2 router")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+
+ logger.info("Configuring redistribute static")
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After configuring them, route is always active with lowest AD"
+ "value and all the nexthop populated in RIB and FIB again "
+ )
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Route with "
+ " lowest AD is missing in RIB".format(tc_name)
+
+ step(
+ "Remove the static route configured with nexthop N1 to N8, one"
+ "by one from running config"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # delete static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ "delete": True,
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After removing the static route with N1 to N8 one by one, "
+ "route become active with next preferred nexthop and nexthop which "
+ "got removed is not shown in RIB and FIB"
+ )
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh_all[addr_type],
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " still present in RIB".format(tc_name)
+
+ step("Configure the static route with nexthop N1 to N8, one by" "one")
+ for addr_type in ADDR_TYPES:
+ # add static routes
+ for nhp in range(1, 9):
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(nhp)][addr_type],
+ "admin_distance": 10 * nhp,
+ }
+ ]
+ }
+ }
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("On R2, static route with lowest AD nexthop installed in FIB")
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Route with "
+ " lowest AD is missing in RIB".format(tc_name)
+
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " with high AD are active in RIB".format(tc_name)
+
+ step("Random shut of the nexthop interfaces")
+ randnum = random.randint(0, 7)
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ input_dict_5 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_5,
+ next_hop=nhip,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \n"
+ "Error: Routes are still present in RIB".format(tc_name)
+
+ step("Random no shut of the nexthop interfaces")
+ for addr_type in ADDR_TYPES:
+ intf = topo["routers"]["r2"]["links"]["r1-link" + str(randnum)]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, True)
+ nhip = NEXT_HOP_IP["nh" + str(randnum + 1)][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_5, next_hop=nhip, protocol=protocol
+ )
+ assert result is True, "Testcase {} : Failed \n"
+ "Error: Routes are missing in RIB".format(tc_name)
+
+ step("Reload the FRR router")
+ # stop/start -> restart FRR router and verify
+ stop_router(tgen, "r2")
+ start_router(tgen, "r2")
+
+ step(
+ "After reload of FRR router, static route installed "
+ "in RIB and FIB properly ."
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": PREFIX1[addr_type],
+ "next_hop": NEXT_HOP_IP["nh1"][addr_type],
+ "admin_distance": 10,
+ }
+ ]
+ }
+ }
+ dut = "r2"
+ protocol = "static"
+ nh = NEXT_HOP_IP["nh1"][addr_type]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_4, next_hop=nh, protocol=protocol, fib=True
+ )
+ assert result is True, "Testcase {} : Failed \nError: Route with "
+ " lowest AD is missing in RIB".format(tc_name)
+
+ nh = []
+ for nhp in range(2, 9):
+ nh.append(NEXT_HOP_IP["nh" + str(nhp)][addr_type])
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ fib=True,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes "
+ " with high AD are active in RIB".format(tc_name)
+
+ step("Remove the redistribute static knob")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static", "delete": True}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ logger.info("Remove redistribute static")
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("verify that routes are deleted from R3 routing table")
+ dut = "r3"
+ protocol = "bgp"
+ result = verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict_4,
+ next_hop=nh,
+ protocol=protocol,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed \nError: Routes are"
+ " strill present in RIB of R3".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+def test_bgp_local_nexthop_p1_tc14_ibgp(request):
+ """
+ Verify BGP did not install the static route when it receive route
+ with local next hop
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+
+ step("Configure BGP IPv4 session between R2 and R3")
+ step("Configure IPv4 static route on R2")
+ reset_config_on_routers(tgen)
+
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_4 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": topo["routers"]["r3"]["links"]["r2-link0"][
+ addr_type
+ ].split("/")[0],
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure redistribute static in the BGP")
+
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify R2 BGP table has IPv4 route")
+ dut = "r2"
+ result = verify_rib(tgen, addr_type, dut, input_dict_4)
+ assert result is True, "Testcase {} : Failed \nError: Routes is"
+ " missing in RIB of R2".format(tc_name)
+
+ step(" Verify route did not install in the R3 BGP table, RIB/FIB")
+ dut = "r3"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_4, expected=False)
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in BGP RIB of R2".format(tc_name)
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_4, expected=False)
+ assert result is not True, "Testcase {} : Failed \nError: Routes is"
+ " still present in RIB of R2".format(tc_name)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py
new file mode 100644
index 0000000000..fdbfad25b3
--- /dev/null
+++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py
@@ -0,0 +1,991 @@
+#!/usr/bin/python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+
+Following tests are covered in the script.
+
+- Verify static route are blocked from route-map and prefix-list
+ applied in BGP nbrs
+"""
+
+import sys
+import json
+import time
+import os
+import pytest
+import platform
+import ipaddress
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from mininet.topo import Topo
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ check_address_types,
+ step,
+ create_prefix_lists,
+ create_route_maps,
+ create_interfaces_cfg,
+ verify_prefix_lists,
+ verify_route_maps,
+)
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ clear_bgp_and_verify,
+ clear_bgp,
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.topotest import version_cmp
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/static_routes_topo4_ibgp.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": "2.2.2.2/32", "ipv6": "22:22::2/128"}
+NEXT_HOP_IP = {}
+
+
+class CreateTopo(Topo):
+ """
+ Test CreateTopo - topology 1.
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function."""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Set up the pytest environment.
+ * `mod`: module name
+ """
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('These tests will not run. (have kernel "{}", '
+ 'requires kernel >= 4.19)'.format(platform.release()))
+ pytest.skip(error_msg)
+
+ # Checking BGP convergence
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ # Api call verify whether BGP is converged
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module(mod):
+ """
+ Teardown the pytest environment.
+
+ * `mod`: module name
+ """
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Tests starting
+#
+#####################################################
+def test_static_routes_rmap_pfxlist_p0_tc7_ibgp(request):
+ """
+ Verify static route are blocked from route-map & prefix-list applied in BGP
+ nbrs
+
+ """
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ tgen = get_topogen()
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ reset_config_on_routers(tgen)
+ step("Configure holddown timer = 1 keep alive = 3 in all the neighbors")
+ step("verify bgp convergence before starting test case")
+
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, bgp_convergence
+ )
+
+ step(
+ "Configure 4 IPv4 and 4 IPv6 nbrs with password with mismatch "
+ " authentication between FRR routers "
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Api call to modfiy BGP timerse
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {"password": "r2"},
+ "r2-link1": {"password": "r2"},
+ "r2-link2": {"password": "r2"},
+ "r2-link3": {"password": "r2"},
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link0": {"password": "r2"},
+ "r2-link1": {"password": "r2"},
+ "r2-link2": {"password": "r2"},
+ "r2-link3": {"password": "r2"},
+ }
+ },
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, deepcopy(input_dict))
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+ clear_bgp(tgen, addr_type, "r2")
+
+ step(" All BGP nbrs are down as authentication is mismatch on both" " the sides")
+
+ bgp_convergence = verify_bgp_convergence(tgen, topo, expected=False)
+ assert bgp_convergence is not True, "Testcase {} : "
+ "Failed \n BGP nbrs must be down. Error: {}".format(tc_name, bgp_convergence)
+
+ step(
+ "Configure 4 IPv4 and 4 IPv6 nbrs with macthing password "
+ " authentication between FRR routers "
+ )
+ for addr_type in ADDR_TYPES:
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {"password": "r1"},
+ "r2-link1": {"password": "r1"},
+ "r2-link2": {"password": "r1"},
+ "r2-link3": {"password": "r1"},
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link0": {"password": "r1"},
+ "r2-link1": {"password": "r1"},
+ "r2-link2": {"password": "r1"},
+ "r2-link3": {"password": "r1"},
+ }
+ },
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, deepcopy(input_dict))
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("All BGP nbrs are up as authentication is matched now")
+ bgp_convergence = verify_bgp_convergence(tgen, topo)
+ assert bgp_convergence is True, "Testcase {} : Failed \n " "Error: {}".format(
+ tc_name, bgp_convergence
+ )
+
+ step("Create prefix list P1 to permit VM3 & deny VM1 v4 & v6 routes")
+ step("Create prefix list P2 to permit VM6 IPv4 and IPv6 routes")
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r2": {
+ "prefix_lists": {
+ addr_type: {
+ "pf_list_1_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": topo["routers"]["r2"]["links"]["vm3"][
+ addr_type
+ ],
+ "action": "permit",
+ },
+ {
+ "seqid": 20,
+ "network": topo["routers"]["r2"]["links"]["vm1"][
+ addr_type
+ ],
+ "action": "deny",
+ },
+ ],
+ "pf_list_2_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": topo["routers"]["r2"]["links"]["vm6"][
+ addr_type
+ ],
+ "action": "permit",
+ }
+ ],
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Prefix list created with matching networks deny or permit "
+ "show ip prefix list"
+ )
+ result = verify_prefix_lists(tgen, input_dict_2)
+ assert result is not True, "Testcase {} : Failed \n"
+ " Error: {}".format(tc_name, result)
+
+ step("Redistribute all the routes (connected, static)")
+ input_dict_2_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2_r2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2_r3 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute connected in Router BGP")
+
+ input_dict_2_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2_r3 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2_r3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_2 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply prefix list P1 on BGP neighbors 1 2 3 4 connected from " "frr r1")
+ # Configure prefix list to bgp neighbor
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link1": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link2": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link3": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply prefix list P2 on BGP nbrs 5 & 6 connected from FRR-2")
+ # Configure prefix list to bgp neighbor
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link1": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link2": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link3": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ clear_bgp_and_verify(tgen, topo, "r2")
+
+ step(
+ "VM1 IPv4 and IPv6 Route which is denied using prefix list is "
+ "not present on FRR1 side routing table , also not able to "
+ "ping the routes show ip route"
+ )
+
+ dut = "r1"
+ protocol = "bgp"
+ ntwk_r2_vm1 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type])
+ ).network
+ )
+ input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+ result4 = verify_rib(
+ tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
+ )
+ assert result4 is not True, "Testcase {} : Failed , VM1 route is "
+ "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+ step(
+ "VM4 and VM6 IPV4 and IPv6 address are present in local and "
+ "FRR2 routing table show ip bgp show ip route"
+ )
+
+ dut = "r2"
+ ntwk_r2_vm6 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type])
+ ).network
+ )
+ input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}}
+ result4 = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result4 is True, "Testcase {} : Failed.\n Error: {}".format(
+ tc_name, result4
+ )
+
+ step("Remove prefix list from all the neighbors")
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link1": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link2": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link3": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_1_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link1": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link2": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ "r2-link3": {
+ "prefix_lists": [
+ {
+ "name": "pf_list_2_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ "delete": True,
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ clear_bgp_and_verify(tgen, topo, "r2")
+
+ step("Create RouteMap_1 with prefix list P1 and weight 50")
+ # Create route map
+ rmap_dict = {
+ "r2": {
+ "route_maps": {
+ "rmap_pf_list_1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {"weight": 50},
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, rmap_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create RouteMap_2 with prefix list P2 and weight 50")
+ # Create route map
+ rmap_dict = {
+ "r2": {
+ "route_maps": {
+ "rmap_pf_list_2_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {"weight": 50},
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_2_{}".format(addr_type)
+ }
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, rmap_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify Route-map created verify using show route-map")
+ # verify rmap_pf_list_1 and rmap_pf_list_2 are present in router r2
+ input_dict = {
+ "r2": {
+ "route_maps": [
+ "rmap_pf_list_1_{}".format(addr_type),
+ "rmap_pf_list_2_{}".format(addr_type),
+ ]
+ }
+ }
+ result = verify_route_maps(tgen, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply policy RouteMap_1 nbrs 1 2 3 4 to FRR 1")
+ # Configure prefix list to bgp neighbor
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link0": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_1_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_1_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_1_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_1_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply policy RouteMap_2 nbrs 5 and 6 to FRR2")
+ # Configure prefix list to bgp neighbor
+ input_dict_4 = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link0": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_2_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_2_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_2_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_pf_list_2_"
+ "{}".format(addr_type),
+ "direction": "out",
+ }
+ ]
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After applying to BGP neighbors verify VM1 IPv4 and IPv6 Route"
+ " which is denied using prefix list is not present on FRR side"
+ " routing table , also not able to ping the routes show ip route"
+ " and VM4 and VM6 IPV4 and IPv6 address are present in local and"
+ " FRR routing table show ip bgp show ip route"
+ )
+
+ dut = "r1"
+ protocol = "bgp"
+ ntwk_r2_vm1 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r2"]["links"]["vm1"][addr_type])
+ ).network
+ )
+ input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+ result4 = verify_rib(
+ tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
+ )
+ assert result4 is not True, "Testcase {} : Failed \n" "Error: {}".format(
+ tc_name, result4
+ )
+
+ step("vm4 should be present in FRR1")
+ dut = "r1"
+ ntwk_r2_vm1 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type])
+ ).network
+ )
+ input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+ result4 = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result4 is True, "Testcase {} : Failed , VM1 route is "
+ "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+ step("vm4 should be present in FRR2")
+ dut = "r2"
+ ntwk_r2_vm1 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r1"]["links"]["vm4"][addr_type])
+ ).network
+ )
+ input_dict = {"r1": {"static_routes": [{"network": ntwk_r2_vm1}]}}
+ result4 = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result4 is True, "Testcase {} : Failed , VM1 route is "
+ "not filtered out via prefix list. \n Error: {}".format(tc_name, result4)
+
+ dut = "r3"
+ protocol = "bgp"
+ ntwk_r2_vm6 = str(
+ ipaddress.ip_interface(
+ u"{}".format(topo["routers"]["r2"]["links"]["vm6"][addr_type])
+ ).network
+ )
+ input_dict = {"r3": {"static_routes": [{"network": ntwk_r2_vm6}]}}
+ result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol)
+ assert result4 is True, "Testcase {} : Failed.\n Error: {}".format(
+ tc_name, result4
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/zebra_netlink/test_zebra_netlink.py b/tests/topotests/zebra_netlink/test_zebra_netlink.py
index 4da5303641..94baf8438f 100644
--- a/tests/topotests/zebra_netlink/test_zebra_netlink.py
+++ b/tests/topotests/zebra_netlink/test_zebra_netlink.py
@@ -118,7 +118,12 @@ def test_zebra_netlink_batching():
r1.vtysh_cmd("sharp install routes 2.1.3.7 nexthop 192.168.1.1 100")
json_file = "{}/r1/v4_route.json".format(CWD)
expected = json.loads(open(json_file).read())
- test_func = partial(topotest.router_json_cmp, r1, "show ip route json", expected,)
+ test_func = partial(
+ topotest.router_json_cmp,
+ r1,
+ "show ip route json",
+ expected,
+ )
_, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
assertmsg = '"r1" JSON output mismatches'
assert result is None, assertmsg
diff --git a/zebra/connected.c b/zebra/connected.c
index 70ea2e3805..c885c533e6 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -402,10 +402,10 @@ void connected_down(struct interface *ifp, struct connected *ifc)
* head.
*/
rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT, 0,
- 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true);
+ 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
rib_delete(afi, SAFI_MULTICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_CONNECT,
- 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false, true);
+ 0, 0, &p, NULL, &nh, 0, zvrf->table_id, 0, 0, false);
/* Schedule LSP forwarding entries for processing, if appropriate. */
if (zvrf->vrf->vrf_id == VRF_DEFAULT) {
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 9d74aeca28..adbdf54c1f 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -1107,7 +1107,7 @@ void rtm_read(struct rt_msghdr *rtm)
if (rtm->rtm_type == RTM_CHANGE)
rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
0, zebra_flags, &p, NULL, NULL, 0, RT_TABLE_MAIN, 0,
- 0, true, false);
+ 0, true);
if (rtm->rtm_type == RTM_GET || rtm->rtm_type == RTM_ADD
|| rtm->rtm_type == RTM_CHANGE)
rib_add(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL, 0,
@@ -1116,7 +1116,7 @@ void rtm_read(struct rt_msghdr *rtm)
else
rib_delete(afi, SAFI_UNICAST, VRF_DEFAULT, ZEBRA_ROUTE_KERNEL,
0, zebra_flags, &p, NULL, &nh, 0, RT_TABLE_MAIN, 0,
- 0, true, false);
+ 0, true);
}
/* Interface function for the kernel routing table updates. Support
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 1f075cfb4b..370dbaa240 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -715,7 +715,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE,
re->table, re->flags, &p, NULL, re->nhe->nhg.nexthop,
re->nhe_id, zvrf->table_id, re->metric, re->distance,
- false, false);
+ false);
return 0;
}
diff --git a/zebra/rib.h b/zebra/rib.h
index fe7073656c..c385d7326c 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -393,7 +393,7 @@ extern void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
struct prefix *p, struct prefix_ipv6 *src_p,
const struct nexthop *nh, uint32_t nhe_id,
uint32_t table_id, uint32_t metric, uint8_t distance,
- bool fromkernel, bool connected_down);
+ bool fromkernel);
extern struct route_entry *rib_match(afi_t afi, safi_t safi, vrf_id_t vrf_id,
union g_addr *addr,
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index c034ea2fd2..c1a0e6ccd1 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -873,7 +873,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
if (nhe_id) {
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags,
&p, &src_p, NULL, nhe_id, table, metric,
- distance, true, false);
+ distance, true);
} else {
if (!tb[RTA_MULTIPATH]) {
struct nexthop nh;
@@ -883,13 +883,13 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
gate, afi, vrf_id);
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
flags, &p, &src_p, &nh, 0, table,
- metric, distance, true, false);
+ metric, distance, true);
} else {
/* XXX: need to compare the entire list of
* nexthops here for NLM_F_APPEND stupidity */
rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0,
flags, &p, &src_p, NULL, 0, table,
- metric, distance, true, false);
+ metric, distance, true);
}
}
}
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index f2ff8d53f2..90c6a24e7b 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2080,7 +2080,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS)
rib_delete(afi, api.safi, zvrf_id(zvrf), api.type, api.instance,
api.flags, &api.prefix, src_p, NULL, 0, table_id, api.metric,
- api.distance, false, false);
+ api.distance, false);
/* Stats */
switch (api.prefix.family) {
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 0aea0b6cfa..f4be9a8504 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -3088,7 +3088,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
unsigned short instance, uint32_t flags, struct prefix *p,
struct prefix_ipv6 *src_p, const struct nexthop *nh,
uint32_t nhe_id, uint32_t table_id, uint32_t metric,
- uint8_t distance, bool fromkernel, bool connected_down)
+ uint8_t distance, bool fromkernel)
{
struct route_table *table;
struct route_node *rn;
@@ -3294,19 +3294,6 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
rib_delnode(rn, same);
}
- /*
- * This is to force an immediate re-eval of this particular
- * node via nexthop tracking. Why? Because there are scenarios
- * where the interface is flapping and the normal queuing methodology
- * will cause down/up events to very very rarely be combined into
- * a non-event from nexthop tracking perspective. Leading
- * to some fun timing situations with upper level routing protocol
- * trying to and failing to install routes during this blip. Especially
- * when zebra is under load.
- */
- if (connected_down)
- zebra_rib_evaluate_rn_nexthops(rn,
- zebra_router_get_next_sequence());
route_unlock_node(rn);
return;
}