summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/.gitignore2
-rw-r--r--tests/bgpd/test_peer_attr.c1
-rw-r--r--tests/lib/script1.lua1
-rw-r--r--tests/lib/test_frrlua.c111
-rw-r--r--tests/lib/test_frrlua.py14
-rw-r--r--tests/lib/test_frrscript.c37
-rw-r--r--tests/lib/test_frrscript.py14
-rw-r--r--tests/subdir.am28
-rw-r--r--tests/topotests/bgp_default_afi_safi/__init__.py (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/__init__.py)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r1/bgpd.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/bgpd.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r1/zebra.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/zebra.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r2/bgpd.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/bgpd.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r2/zebra.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/zebra.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r3/bgpd.conf5
-rw-r--r--tests/topotests/bgp_default_afi_safi/r3/zebra.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/zebra.conf)0
-rw-r--r--tests/topotests/bgp_default_afi_safi/r4/bgpd.conf (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/bgpd.conf)1
-rw-r--r--tests/topotests/bgp_default_afi_safi/r4/zebra.conf6
-rw-r--r--tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py (renamed from tests/topotests/bgp_default_ipv4_ipv6_unicast/test_bgp-default-ipv4-ipv6-unicast.py)43
-rw-r--r--tests/topotests/lib/bgp.py34
-rw-r--r--tests/topotests/lib/common_config.py195
-rw-r--r--tests/topotests/lib/ospf.py24
-rw-r--r--tests/topotests/lib/pim.py36
-rw-r--r--tests/topotests/msdp_mesh_topo1/r1/pimd.conf1
-rw-r--r--tests/topotests/msdp_mesh_topo1/r2/pimd.conf1
-rw-r--r--tests/topotests/msdp_mesh_topo1/r3/pimd.conf1
-rw-r--r--tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py2
-rw-r--r--tests/topotests/msdp_topo1/__init__.py0
-rw-r--r--tests/topotests/msdp_topo1/r1/bgpd.conf8
-rw-r--r--tests/topotests/msdp_topo1/r1/pimd.conf21
-rw-r--r--tests/topotests/msdp_topo1/r1/zebra.conf14
-rw-r--r--tests/topotests/msdp_topo1/r2/bgpd.conf8
-rw-r--r--tests/topotests/msdp_topo1/r2/pimd.conf17
-rw-r--r--tests/topotests/msdp_topo1/r2/zebra.conf11
-rw-r--r--tests/topotests/msdp_topo1/r3/bgpd.conf8
-rw-r--r--tests/topotests/msdp_topo1/r3/pimd.conf17
-rw-r--r--tests/topotests/msdp_topo1/r3/zebra.conf11
-rw-r--r--tests/topotests/msdp_topo1/r4/bgpd.conf9
-rw-r--r--tests/topotests/msdp_topo1/r4/pimd.conf21
-rw-r--r--tests/topotests/msdp_topo1/r4/zebra.conf14
-rwxr-xr-xtests/topotests/msdp_topo1/test_msdp_topo1.py499
-rw-r--r--tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py3
-rwxr-xr-xtests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py7
-rwxr-xr-xtests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py116
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_authentication.py8
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py8
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py4
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py4
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py2
-rw-r--r--tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py9
-rw-r--r--tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py11
50 files changed, 1181 insertions, 206 deletions
diff --git a/tests/.gitignore b/tests/.gitignore
index fb2edc939a..3fad1b0813 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -25,6 +25,8 @@
/lib/test_atomlist
/lib/test_buffer
/lib/test_checksum
+/lib/test_frrscript
+/lib/test_frrlua
/lib/test_graph
/lib/test_heavy
/lib/test_heavy_thread
diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c
index 44b55a2381..45e9912a31 100644
--- a/tests/bgpd/test_peer_attr.c
+++ b/tests/bgpd/test_peer_attr.c
@@ -31,6 +31,7 @@
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_network.h"
#include "lib/routing_nb.h"
+#include "lib/northbound_cli.h"
#include "bgpd/bgp_nb.h"
#ifdef ENABLE_BGP_VNC
diff --git a/tests/lib/script1.lua b/tests/lib/script1.lua
new file mode 100644
index 0000000000..e9ebc29bd9
--- /dev/null
+++ b/tests/lib/script1.lua
@@ -0,0 +1 @@
+a = a + b
diff --git a/tests/lib/test_frrlua.c b/tests/lib/test_frrlua.c
new file mode 100644
index 0000000000..a81446f9ca
--- /dev/null
+++ b/tests/lib/test_frrlua.c
@@ -0,0 +1,111 @@
+/*
+ * frrlua unit tests
+ * Copyright (C) 2021 Donald Lee
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+#include "string.h"
+#include "stdio.h"
+#include "lib/frrlua.h"
+
+static void test_encode_decode(void)
+{
+ lua_State *L = luaL_newstate();
+
+ long long a = 123;
+ long long b = a;
+
+ lua_pushintegerp(L, &a);
+ lua_decode_integerp(L, -1, &a);
+ assert(a == b);
+ assert(lua_gettop(L) == 0);
+
+ time_t time_a = 100;
+ time_t time_b = time_a;
+
+ lua_pushtimet(L, &time_a);
+ lua_decode_timet(L, -1, &time_a);
+ assert(time_a == time_b);
+ assert(lua_gettop(L) == 0);
+
+ char str_b[] = "Hello", str_a[6];
+
+ strlcpy(str_a, str_b, sizeof(str_b));
+ lua_pushstring_wrapper(L, str_a);
+ lua_decode_stringp(L, -1, str_a);
+ assert(strncmp(str_a, str_b, sizeof(str_b)) == 0);
+ assert(lua_gettop(L) == 0);
+
+ char p_b_str[] = "10.0.0.0/24", p_a_str[12];
+ struct prefix p_a;
+
+ strlcpy(p_a_str, p_b_str, sizeof(p_b_str));
+ str2prefix(p_a_str, &p_a);
+ lua_pushprefix(L, &p_a);
+ lua_decode_prefix(L, -1, &p_a);
+ prefix2str(&p_a, p_a_str, sizeof(p_b_str));
+ assert(strncmp(p_a_str, p_b_str, sizeof(p_b_str)) == 0);
+ assert(lua_gettop(L) == 0);
+
+ struct interface ifp_a;
+ struct interface ifp_b = ifp_a;
+
+ lua_pushinterface(L, &ifp_a);
+ lua_decode_interface(L, -1, &ifp_a);
+ assert(strncmp(ifp_a.name, ifp_b.name, sizeof(ifp_b.name)) == 0);
+ assert(ifp_a.ifindex == ifp_b.ifindex);
+ assert(ifp_a.status == ifp_b.status);
+ assert(ifp_a.flags == ifp_b.flags);
+ assert(ifp_a.metric == ifp_b.metric);
+ assert(ifp_a.speed == ifp_b.speed);
+ assert(ifp_a.mtu == ifp_b.mtu);
+ assert(ifp_a.mtu6 == ifp_b.mtu6);
+ assert(ifp_a.bandwidth == ifp_b.bandwidth);
+ assert(ifp_a.link_ifindex == ifp_b.link_ifindex);
+ assert(ifp_a.ll_type == ifp_b.ll_type);
+ assert(lua_gettop(L) == 0);
+
+ struct in_addr addr_a;
+ struct in_addr addr_b = addr_a;
+
+ lua_pushinaddr(L, &addr_a);
+ lua_decode_inaddr(L, -1, &addr_a);
+ assert(addr_a.s_addr == addr_b.s_addr);
+ assert(lua_gettop(L) == 0);
+
+ struct in6_addr in6addr_a;
+ struct in6_addr in6addr_b = in6addr_a;
+
+ lua_pushin6addr(L, &in6addr_a);
+ lua_decode_in6addr(L, -1, &in6addr_a);
+ assert(in6addr_cmp(&in6addr_a, &in6addr_b) == 0);
+ assert(lua_gettop(L) == 0);
+
+ union sockunion su_a, su_b;
+
+ memset(&su_a, 0, sizeof(union sockunion));
+ memset(&su_b, 0, sizeof(union sockunion));
+ lua_pushsockunion(L, &su_a);
+ lua_decode_sockunion(L, -1, &su_a);
+ assert(sockunion_cmp(&su_a, &su_b) == 0);
+ assert(lua_gettop(L) == 0);
+}
+
+int main(int argc, char **argv)
+{
+ test_encode_decode();
+}
diff --git a/tests/lib/test_frrlua.py b/tests/lib/test_frrlua.py
new file mode 100644
index 0000000000..2f6ddc1c07
--- /dev/null
+++ b/tests/lib/test_frrlua.py
@@ -0,0 +1,14 @@
+import frrtest
+import pytest
+
+if 'S["SCRIPTING_TRUE"]=""\n' not in open("../config.status").readlines():
+ class TestFrrlua:
+ @pytest.mark.skipif(True, reason="Test unsupported")
+ def test_exit_cleanly(self):
+ pass
+else:
+
+ class TestFrrlua(frrtest.TestMultiOut):
+ program = "./test_frrlua"
+
+ TestFrrlua.exit_cleanly()
diff --git a/tests/lib/test_frrscript.c b/tests/lib/test_frrscript.c
new file mode 100644
index 0000000000..bd75cc5552
--- /dev/null
+++ b/tests/lib/test_frrscript.c
@@ -0,0 +1,37 @@
+/*
+ * frrscript unit tests
+ * Copyright (C) 2021 Donald Lee
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "lib/frrscript.h"
+
+int main(int argc, char **argv)
+{
+ frrscript_init("./lib");
+
+ struct frrscript *fs = frrscript_load("script1", NULL);
+ long long a = 100, b = 200;
+ int result = frrscript_call(fs, ("a", &a), ("b", &b));
+
+ assert(result == 0);
+ assert(a == 300);
+ assert(b == 200);
+
+ return 0;
+}
diff --git a/tests/lib/test_frrscript.py b/tests/lib/test_frrscript.py
new file mode 100644
index 0000000000..046d97b014
--- /dev/null
+++ b/tests/lib/test_frrscript.py
@@ -0,0 +1,14 @@
+import frrtest
+import pytest
+
+if 'S["SCRIPTING_TRUE"]=""\n' not in open("../config.status").readlines():
+ class TestFrrscript:
+ @pytest.mark.skipif(True, reason="Test unsupported")
+ def test_exit_cleanly(self):
+ pass
+else:
+
+ class TestFrrscript(frrtest.TestMultiOut):
+ program = "./test_frrscript"
+
+ TestFrrscript.exit_cleanly()
diff --git a/tests/subdir.am b/tests/subdir.am
index ca477851e3..c2153140f5 100644
--- a/tests/subdir.am
+++ b/tests/subdir.am
@@ -59,6 +59,15 @@ TESTS_ZEBRA =
IGNORE_ZEBRA = --ignore=zebra/
endif
+if SCRIPTING
+TESTS_SCRIPTING = \
+ tests/lib/test_frrlua \
+ tests/lib/test_frrscript \
+ #end
+else
+TESTS_SCRIPTING =
+endif
+
clippy_scan += \
tests/lib/cli/test_cli.c \
tests/ospf6d/test_lsdb.c \
@@ -104,6 +113,7 @@ check_PROGRAMS = \
$(TESTS_OSPFD) \
$(TESTS_OSPF6D) \
$(TESTS_ZEBRA) \
+ $(TESTS_SCRIPTING) \
# end
if GRPC
@@ -289,6 +299,16 @@ tests_lib_test_checksum_CFLAGS = $(TESTS_CFLAGS)
tests_lib_test_checksum_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_lib_test_checksum_LDADD = $(ALL_TESTS_LDADD)
tests_lib_test_checksum_SOURCES = tests/lib/test_checksum.c
+if SCRIPTING
+tests_lib_test_frrlua_CFLAGS = $(TESTS_CFLAGS)
+tests_lib_test_frrlua_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_test_frrlua_LDADD = $(ALL_TESTS_LDADD)
+tests_lib_test_frrlua_SOURCES = tests/lib/test_frrlua.c
+tests_lib_test_frrscript_CFLAGS = $(TESTS_CFLAGS)
+tests_lib_test_frrscript_CPPFLAGS = $(TESTS_CPPFLAGS)
+tests_lib_test_frrscript_LDADD = $(ALL_TESTS_LDADD)
+tests_lib_test_frrscript_SOURCES = tests/lib/test_frrscript.c
+endif
tests_lib_test_graph_CFLAGS = $(TESTS_CFLAGS)
tests_lib_test_graph_CPPFLAGS = $(TESTS_CPPFLAGS)
tests_lib_test_graph_LDADD = $(ALL_TESTS_LDADD)
@@ -464,6 +484,14 @@ EXTRA_DIST += \
tests/zebra/test_lm_plugin.refout \
# end
+
+if SCRIPTING
+EXTRA_DIST += \
+ tests/lib/test_frrscript.py \
+ tests/lib/test_frrlua.py \
+ #end
+endif
+
.PHONY: tests/tests.xml
tests/tests.xml: $(check_PROGRAMS)
( cd tests; $(PYTHON) ../$(srcdir)/tests/runtests.py --junitxml=tests.xml -v ../$(srcdir)/tests $(IGNORE_BGPD) $(IGNORE_ISISD) $(IGNORE_OSPF6D); )
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/__init__.py b/tests/topotests/bgp_default_afi_safi/__init__.py
index e69de29bb2..e69de29bb2 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/__init__.py
+++ b/tests/topotests/bgp_default_afi_safi/__init__.py
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/bgpd.conf b/tests/topotests/bgp_default_afi_safi/r1/bgpd.conf
index bf39152ea8..bf39152ea8 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/bgpd.conf
+++ b/tests/topotests/bgp_default_afi_safi/r1/bgpd.conf
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/zebra.conf b/tests/topotests/bgp_default_afi_safi/r1/zebra.conf
index 697765168d..697765168d 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r1/zebra.conf
+++ b/tests/topotests/bgp_default_afi_safi/r1/zebra.conf
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/bgpd.conf b/tests/topotests/bgp_default_afi_safi/r2/bgpd.conf
index abbd1b86fa..abbd1b86fa 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/bgpd.conf
+++ b/tests/topotests/bgp_default_afi_safi/r2/bgpd.conf
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/zebra.conf b/tests/topotests/bgp_default_afi_safi/r2/zebra.conf
index 606c17bec9..606c17bec9 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r2/zebra.conf
+++ b/tests/topotests/bgp_default_afi_safi/r2/zebra.conf
diff --git a/tests/topotests/bgp_default_afi_safi/r3/bgpd.conf b/tests/topotests/bgp_default_afi_safi/r3/bgpd.conf
new file mode 100644
index 0000000000..f3ec3f06c5
--- /dev/null
+++ b/tests/topotests/bgp_default_afi_safi/r3/bgpd.conf
@@ -0,0 +1,5 @@
+!
+router bgp 65001
+ no bgp default ipv4-unicast
+ bgp default l2vpn-evpn
+!
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/zebra.conf b/tests/topotests/bgp_default_afi_safi/r3/zebra.conf
index e9fdfb70c5..e9fdfb70c5 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/zebra.conf
+++ b/tests/topotests/bgp_default_afi_safi/r3/zebra.conf
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/bgpd.conf b/tests/topotests/bgp_default_afi_safi/r4/bgpd.conf
index a405c047ca..8a6af55ee7 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/r3/bgpd.conf
+++ b/tests/topotests/bgp_default_afi_safi/r4/bgpd.conf
@@ -1,4 +1,5 @@
!
router bgp 65001
bgp default ipv6-unicast
+ bgp default l2vpn-evpn
!
diff --git a/tests/topotests/bgp_default_afi_safi/r4/zebra.conf b/tests/topotests/bgp_default_afi_safi/r4/zebra.conf
new file mode 100644
index 0000000000..e9fdfb70c5
--- /dev/null
+++ b/tests/topotests/bgp_default_afi_safi/r4/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r3-eth0
+ ip address 192.168.255.3/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_default_ipv4_ipv6_unicast/test_bgp-default-ipv4-ipv6-unicast.py b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py
index f9aa94fd14..28117b7fe4 100644
--- a/tests/topotests/bgp_default_ipv4_ipv6_unicast/test_bgp-default-ipv4-ipv6-unicast.py
+++ b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py
@@ -20,12 +20,13 @@
#
"""
-Test if `bgp default ipv4-unicast` and `bgp default ipv6-unicast`
-commands work as expected.
+Test if `bgp default ipv4-unicast`, `bgp default ipv6-unicast`
+and `bgp default l2vpn-evpn` commands work as expected.
STEP 1: 'Check if neighbor 192.168.255.254 is enabled for ipv4 address-family only'
STEP 2: 'Check if neighbor 192.168.255.254 is enabled for ipv6 address-family only'
-STEP 3: 'Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families'
+STEP 3: 'Check if neighbor 192.168.255.254 is enabled for l2vpn evpn address-family only'
+STEP 4: 'Check if neighbor 192.168.255.254 is enabled for ipv4/ipv6 unicast and l2vpn evpn address-families'
"""
import os
@@ -98,7 +99,7 @@ def test_bgp_default_ipv4_ipv6_unicast():
output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp summary json"))
- if "ipv4Unicast" in output and "ipv6Unicast" not in output:
+ if len(output.keys()) == 1 and "ipv4Unicast" in output:
return True
return False
@@ -113,28 +114,48 @@ def test_bgp_default_ipv4_ipv6_unicast():
output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp summary json"))
- if "ipv4Unicast" not in output and "ipv6Unicast" in output:
+ if len(output.keys()) == 1 and "ipv6Unicast" in output:
return True
return False
assert _bgp_neighbor_ipv6_af_only() == True
- step(
- "Check if neighbor 192.168.255.254 is enabled for ipv4 and ipv6 address-families"
- )
+ step("Check if neighbor 192.168.255.254 is enabled for evpn address-family only")
- def _bgp_neighbor_ipv4_and_ipv6_af():
+ def _bgp_neighbor_evpn_af_only():
tgen.gears["r3"].vtysh_cmd(
"conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
)
output = json.loads(tgen.gears["r3"].vtysh_cmd("show bgp summary json"))
- if "ipv4Unicast" in output and "ipv6Unicast" in output:
+ if len(output.keys()) == 1 and "l2VpnEvpn" in output:
+ return True
+ return False
+
+ assert _bgp_neighbor_evpn_af_only() == True
+
+ step(
+ "Check if neighbor 192.168.255.254 is enabled for ipv4/ipv6 unicast and evpn address-families"
+ )
+
+ def _bgp_neighbor_ipv4_ipv6_and_evpn_af():
+ tgen.gears["r4"].vtysh_cmd(
+ "conf t\nrouter bgp\nneighbor 192.168.255.254 remote-as external"
+ )
+
+ output = json.loads(tgen.gears["r4"].vtysh_cmd("show bgp summary json"))
+
+ if (
+ len(output.keys()) == 3
+ and "ipv4Unicast" in output
+ and "ipv6Unicast" in output
+ and "l2VpnEvpn" in output
+ ):
return True
return False
- assert _bgp_neighbor_ipv4_and_ipv6_af() == True
+ assert _bgp_neighbor_ipv4_ipv6_and_evpn_af() == True
if __name__ == "__main__":
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index db7b3586f1..a236a916b5 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -989,7 +989,7 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict):
#############################################
# Verification APIs
#############################################
-@retry(attempts=4, wait=2, return_is_str=True)
+@retry(retry_timeout=8)
def verify_router_id(tgen, topo, input_dict, expected=True):
"""
Running command "show ip bgp json" for DUT and reading router-id
@@ -1061,7 +1061,7 @@ def verify_router_id(tgen, topo, input_dict, expected=True):
return True
-@retry(attempts=50, wait=3, return_is_str=True)
+@retry(retry_timeout=150)
def verify_bgp_convergence(tgen, topo, dut=None, expected=True):
"""
API will verify if BGP is converged with in the given time frame.
@@ -1266,7 +1266,7 @@ def verify_bgp_convergence(tgen, topo, dut=None, expected=True):
return True
-@retry(attempts=4, wait=4, return_is_str=True)
+@retry(retry_timeout=16)
def verify_bgp_community(
tgen, addr_type, router, network, input_dict=None, vrf=None, bestpath=False, expected=True
):
@@ -1427,7 +1427,7 @@ def modify_as_number(tgen, topo, input_dict):
return True
-@retry(attempts=4, wait=2, return_is_str=True)
+@retry(retry_timeout=8)
def verify_as_numbers(tgen, topo, input_dict, expected=True):
"""
This API is to verify AS numbers for given DUT by running
@@ -1527,7 +1527,7 @@ def verify_as_numbers(tgen, topo, input_dict, expected=True):
return True
-@retry(attempts=50, wait=3, return_is_str=True)
+@retry(retry_timeout=150)
def verify_bgp_convergence_from_running_config(tgen, dut=None, expected=True):
"""
API to verify BGP convergence b/w loopback and physical interface.
@@ -2083,7 +2083,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
return True
-@retry(attempts=4, wait=4, return_is_str=True)
+@retry(retry_timeout=16)
def verify_bgp_attributes(
tgen,
addr_type,
@@ -2223,7 +2223,7 @@ def verify_bgp_attributes(
return True
-@retry(attempts=4, wait=2, return_is_str=True)
+@retry(retry_timeout=8)
def verify_best_path_as_per_bgp_attribute(
tgen, addr_type, router, input_dict, attribute, expected=True
):
@@ -2429,7 +2429,7 @@ def verify_best_path_as_per_bgp_attribute(
return True
-@retry(attempts=5, wait=2, return_is_str=True)
+@retry(retry_timeout=10)
def verify_best_path_as_per_admin_distance(
tgen, addr_type, router, input_dict, attribute, expected=True
):
@@ -2543,7 +2543,7 @@ def verify_best_path_as_per_admin_distance(
return True
-@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+@retry(retry_timeout=10, initial_wait=2)
def verify_bgp_rib(
tgen, addr_type, dut, input_dict, next_hop=None, aspath=None, multi_nh=None, expected=True
):
@@ -2846,7 +2846,7 @@ def verify_bgp_rib(
return True
-@retry(attempts=5, wait=2, return_is_str=True)
+@retry(retry_timeout=10)
def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
"""
This API is to verify verify_graceful_restart configuration of DUT and
@@ -3096,7 +3096,7 @@ def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer, expect
return True
-@retry(attempts=5, wait=2, return_is_str=True)
+@retry(retry_timeout=10)
def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
"""
This API is to verify r_bit in the BGP gr capability advertised
@@ -3216,7 +3216,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
return True
-@retry(attempts=5, wait=2, return_is_str=True)
+@retry(retry_timeout=10)
def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
"""
This API is to verify EOR
@@ -3379,7 +3379,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
return True
-@retry(attempts=4, wait=2, return_is_str=True)
+@retry(retry_timeout=8)
def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
"""
This API is to verify f_bit in the BGP gr capability advertised
@@ -3520,7 +3520,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True):
return True
-@retry(attempts=5, wait=2, return_is_str=True)
+@retry(retry_timeout=10)
def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer):
"""
This API is to verify graceful restart timers, configured and recieved
@@ -3648,7 +3648,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer)
return True
-@retry(attempts=4, wait=2, return_is_str=True)
+@retry(retry_timeout=8)
def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut, expected=True):
"""
This API is to verify gr_address_family in the BGP gr capability advertised
@@ -3739,7 +3739,7 @@ def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut, expected=T
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
-@retry(attempts=6, wait=2, return_is_str=True)
+@retry(retry_timeout=12)
def verify_attributes_for_evpn_routes(
tgen,
topo,
@@ -4139,7 +4139,7 @@ def verify_attributes_for_evpn_routes(
return False
-@retry(attempts=5, wait=2, return_is_str=True)
+@retry(retry_timeout=10)
def verify_evpn_routes(
tgen, topo, dut, input_dict, routeType=5, EthTag=0, next_hop=None, expected=True
):
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 3f78f020bc..d659b8d52d 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -19,7 +19,7 @@
#
from collections import OrderedDict
-from datetime import datetime
+from datetime import datetime, timedelta
from time import sleep
from copy import deepcopy
from subprocess import call
@@ -37,12 +37,14 @@ import socket
import ipaddress
import platform
-if sys.version_info[0] > 2:
- import io
- import configparser
-else:
- import StringIO
+try:
+ # Imports from python2
+ from StringIO import StringIO
import ConfigParser as configparser
+except ImportError:
+ # Imports from python3
+ from io import StringIO
+ import configparser
from lib.topolog import logger, logger_config
from lib.topogen import TopoRouter, get_topogen
@@ -136,6 +138,12 @@ DEBUG_LOGS = {
],
}
+def is_string(value):
+ try:
+ return isinstance(value, basestring)
+ except NameError:
+ return isinstance(value, str)
+
if config.has_option("topogen", "verbosity"):
loglevel = config.get("topogen", "verbosity")
loglevel = loglevel.upper()
@@ -448,16 +456,6 @@ def check_router_status(tgen):
return True
-def getStrIO():
- """
- Return a StringIO object appropriate for the current python version.
- """
- if sys.version_info[0] > 2:
- return io.StringIO()
- else:
- return StringIO.StringIO()
-
-
def reset_config_on_routers(tgen, routerName=None):
"""
Resets configuration on routers to the snapshot created using input JSON
@@ -529,7 +527,7 @@ def reset_config_on_routers(tgen, routerName=None):
raise InvalidCLIError("Unknown error in %s", output)
f = open(dname, "r")
- delta = getStrIO()
+ delta = StringIO()
delta.write("configure terminal\n")
t_delta = f.read()
@@ -563,7 +561,7 @@ def reset_config_on_routers(tgen, routerName=None):
output = router.vtysh_multicmd(delta.getvalue(), pretty_output=False)
delta.close()
- delta = getStrIO()
+ delta = StringIO()
cfg = router.run("vtysh -c 'show running'")
for line in cfg.split("\n"):
line = line.strip()
@@ -714,20 +712,36 @@ def generate_support_bundle():
tgen = get_topogen()
router_list = tgen.routers()
- test_name = sys._getframe(2).f_code.co_name
+ test_name = os.environ.get('PYTEST_CURRENT_TEST').split(':')[-1].split(' ')[0]
+
TMPDIR = os.path.join(LOGDIR, tgen.modname)
+ bundle_procs = {}
for rname, rnode in router_list.items():
- logger.info("Generating support bundle for {}".format(rname))
+ logger.info("Spawn collection of support bundle for %s", rname)
rnode.run("mkdir -p /var/log/frr")
+ bundle_procs[rname] = tgen.net[rname].popen(
+ "/usr/lib/frr/generate_support_bundle.py",
+ stdin=None,
+ stdout=SUB_PIPE,
+ stderr=SUB_PIPE,
+ )
- # Support only python3 going forward
- bundle_log = rnode.run("env python3 /usr/lib/frr/generate_support_bundle.py")
-
- logger.info(bundle_log)
-
+ for rname, rnode in router_list.items():
dst_bundle = "{}/{}/support_bundles/{}".format(TMPDIR, rname, test_name)
src_bundle = "/var/log/frr"
+
+ output, error = bundle_procs[rname].communicate()
+
+ logger.info("Saving support bundle for %s", rname)
+ if output:
+ logger.info(
+ "Output from collecting support bundle for %s:\n%s", rname, output
+ )
+ if error:
+ logger.warning(
+ "Error from collecting support bundle for %s:\n%s", rname, error
+ )
rnode.run("rm -rf {}".format(dst_bundle))
rnode.run("mkdir -p {}".format(dst_bundle))
rnode.run("mv -f {}/* {}".format(src_bundle, dst_bundle))
@@ -1619,60 +1633,99 @@ def interface_status(tgen, topo, input_dict):
return True
-def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict=False):
+def retry(retry_timeout, initial_wait=0, expected=True, diag_pct=0.75):
"""
- Retries function execution, if return is an errormsg or exception
-
- * `attempts`: Number of attempts to make
- * `wait`: Number of seconds to wait between each attempt
- * `return_is_str`: Return val is an errormsg in case of failure
- * `initial_wait`: Sleeps for this much seconds before executing function
-
+ Fixture: Retries function while it's return value is an errormsg (str), False, or it raises an exception.
+
+ * `retry_timeout`: Retry for at least this many seconds; after waiting initial_wait seconds
+ * `initial_wait`: Sleeps for this many seconds before first executing function
+ * `expected`: if False then the return logic is inverted, except for exceptions,
+ (i.e., a False or errmsg (str) function return ends the retry loop,
+ and returns that False or str value)
+ * `diag_pct`: Percentage of `retry_timeout` to keep testing after negative result would have
+ been returned in order to see if a positive result comes after. This is an
+ important diagnostic tool, and normally should not be disabled. Calls to wrapped
+ functions though, can override the `diag_pct` value to make it larger in case more
+ diagnostic retrying is appropriate.
"""
def _retry(func):
@wraps(func)
def func_retry(*args, **kwargs):
- _wait = kwargs.pop("wait", wait)
- _attempts = kwargs.pop("attempts", attempts)
- _attempts = int(_attempts)
- if _attempts < 0:
- raise ValueError("attempts must be 0 or greater")
+ # We will continue to retry diag_pct of the timeout value to see if test would have passed with a
+ # longer retry timeout value.
+ saved_failure = None
+
+ retry_sleep = 2
+
+ # Allow the wrapped function's args to override the fixtures
+ _retry_timeout = kwargs.pop("retry_timeout", retry_timeout)
+ _expected = kwargs.pop("expected", expected)
+ _initial_wait = kwargs.pop("initial_wait", initial_wait)
+ _diag_pct = kwargs.pop("diag_pct", diag_pct)
+
+ start_time = datetime.now()
+ retry_until = datetime.now() + timedelta(seconds=_retry_timeout + _initial_wait)
if initial_wait > 0:
logger.info("Waiting for [%s]s as initial delay", initial_wait)
sleep(initial_wait)
- _return_is_str = kwargs.pop("return_is_str", return_is_str)
- _return_is_dict = kwargs.pop("return_is_str", return_is_dict)
- _expected = kwargs.setdefault("expected", True)
- kwargs.pop("expected")
- for i in range(1, _attempts + 1):
+ invert_logic = not _expected
+ while True:
+ seconds_left = (retry_until - datetime.now()).total_seconds()
try:
ret = func(*args, **kwargs)
logger.debug("Function returned %s", ret)
- if _return_is_str and isinstance(ret, bool) and _expected:
- return ret
- if (
- isinstance(ret, str) or isinstance(ret, unicode)
- ) and _expected is False:
- return ret
- if _return_is_dict and isinstance(ret, dict):
- return ret
-
- if _attempts == i:
- generate_support_bundle()
- return ret
- except Exception as err:
- if _attempts == i:
- generate_support_bundle()
- logger.info("Max number of attempts (%r) reached", _attempts)
- raise
- else:
- logger.info("Function returned %s", err)
- if i < _attempts:
- logger.info("Retry [#%r] after sleeping for %ss" % (i, _wait))
- sleep(_wait)
+
+ negative_result = ret is False or is_string(ret)
+ if negative_result == invert_logic:
+ # Simple case, successful result in time
+ if not saved_failure:
+ return ret
+
+ # Positive result, but happened after timeout failure, very important to
+ # note for fixing tests.
+ logger.warning("RETRY DIAGNOSTIC: SUCCEED after FAILED with requested timeout of %.1fs; however, succeeded in %.1fs, investigate timeout timing",
+ _retry_timeout, (datetime.now() - start_time).total_seconds())
+ if isinstance(saved_failure, Exception):
+ raise saved_failure # pylint: disable=E0702
+ return saved_failure
+
+ except Exception as error:
+ logger.info("Function raised exception: %s", str(error))
+ ret = error
+
+ if seconds_left < 0 and saved_failure:
+ logger.info("RETRY DIAGNOSTIC: Retry timeout reached, still failing")
+ if isinstance(saved_failure, Exception):
+ raise saved_failure # pylint: disable=E0702
+ return saved_failure
+
+ if seconds_left < 0:
+ logger.info("Retry timeout of %ds reached", _retry_timeout)
+
+ saved_failure = ret
+ retry_extra_delta = timedelta(seconds=seconds_left + _retry_timeout * _diag_pct)
+ retry_until = datetime.now() + retry_extra_delta
+ seconds_left = retry_extra_delta.total_seconds()
+
+ # Generate bundle after setting remaining diagnostic retry time
+ generate_support_bundle()
+
+ # If user has disabled diagnostic retries return now
+ if not _diag_pct:
+ if isinstance(saved_failure, Exception):
+ raise saved_failure
+ return saved_failure
+
+ if saved_failure:
+ logger.info("RETRY DIAG: [failure] Sleeping %ds until next retry with %.1f retry time left - too see if timeout was too short",
+ retry_sleep, seconds_left)
+ else:
+ logger.info("Sleeping %ds until next retry with %.1f retry time left",
+ retry_sleep, seconds_left)
+ sleep(retry_sleep)
func_retry._original = func
return func_retry
@@ -2881,7 +2934,7 @@ def configure_interface_mac(tgen, input_dict):
#############################################
# Verification APIs
#############################################
-@retry(attempts=6, wait=2, return_is_str=True)
+@retry(retry_timeout=12)
def verify_rib(
tgen,
addr_type,
@@ -3290,7 +3343,7 @@ def verify_rib(
return True
-@retry(attempts=6, wait=2, return_is_str=True)
+@retry(retry_timeout=12)
def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
"""
Data will be read from input_dict or input JSON file, API will generate
@@ -3694,7 +3747,7 @@ def verify_prefix_lists(tgen, input_dict):
return True
-@retry(attempts=3, wait=4, return_is_str=True)
+@retry(retry_timeout=12)
def verify_route_maps(tgen, input_dict):
"""
Running "show route-map" command and verifying given route-map
@@ -3746,7 +3799,7 @@ def verify_route_maps(tgen, input_dict):
return True
-@retry(attempts=4, wait=4, return_is_str=True)
+@retry(retry_timeout=16)
def verify_bgp_community(tgen, addr_type, router, network, input_dict=None):
"""
API to veiryf BGP large community is attached in route for any given
@@ -3982,7 +4035,7 @@ def verify_cli_json(tgen, input_dict):
return True
-@retry(attempts=3, wait=4, return_is_str=True)
+@retry(retry_timeout=12)
def verify_evpn_vni(tgen, input_dict):
"""
API to verify evpn vni details using "show evpn vni detail json"
@@ -4100,7 +4153,7 @@ def verify_evpn_vni(tgen, input_dict):
return False
-@retry(attempts=3, wait=4, return_is_str=True)
+@retry(retry_timeout=12)
def verify_vrf_vni(tgen, input_dict):
"""
API to verify vrf vni details using "show vrf vni json"
diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py
index 3f39b93d8c..dc9fe0fcca 100644
--- a/tests/topotests/lib/ospf.py
+++ b/tests/topotests/lib/ospf.py
@@ -579,7 +579,7 @@ def redistribute_ospf(tgen, topo, dut, route_type, **kwargs):
################################
# Verification procs
################################
-@retry(attempts=40, wait=2, return_is_str=True)
+@retry(retry_timeout=80)
def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False, expected=True):
"""
This API is to verify ospf neighborship by running
@@ -774,7 +774,7 @@ def verify_ospf_neighbor(tgen, topo, dut=None, input_dict=None, lan=False, expec
################################
# Verification procs
################################
-@retry(attempts=10, wait=2, return_is_str=True)
+@retry(retry_timeout=20)
def verify_ospf6_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
"""
This API is to verify ospf neighborship by running
@@ -959,7 +959,7 @@ def verify_ospf6_neighbor(tgen, topo, dut=None, input_dict=None, lan=False):
return result
-@retry(attempts=21, wait=2, return_is_str=True)
+@retry(retry_timeout=40)
def verify_ospf_rib(
tgen, dut, input_dict, next_hop=None, tag=None, metric=None, fib=None, expected=True
):
@@ -1236,7 +1236,7 @@ def verify_ospf_rib(
return result
-@retry(attempts=10, wait=2, return_is_str=True)
+@retry(retry_timeout=20)
def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None, expected=True):
"""
This API is to verify ospf routes by running
@@ -1326,7 +1326,7 @@ def verify_ospf_interface(tgen, topo, dut=None, lan=False, input_dict=None, expe
return result
-@retry(attempts=11, wait=2, return_is_str=True)
+@retry(retry_timeout=20)
def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
"""
This API is to verify ospf lsa's by running
@@ -1490,7 +1490,7 @@ def verify_ospf_database(tgen, topo, dut, input_dict, expected=True):
return result
-@retry(attempts=10, wait=2, return_is_str=True)
+@retry(retry_timeout=20)
def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
"""
This API is to verify ospf routes by running
@@ -1571,7 +1571,7 @@ def verify_ospf_summary(tgen, topo, dut, input_dict, expected=True):
-@retry(attempts=10, wait=3, return_is_str=True)
+@retry(retry_timeout=30)
def verify_ospf6_rib(tgen, dut, input_dict, next_hop=None,
tag=None, metric=None, fib=None):
"""
@@ -1811,7 +1811,7 @@ def verify_ospf6_rib(tgen, dut, input_dict, next_hop=None,
return result
-@retry(attempts=3, wait=2, return_is_str=True)
+@retry(retry_timeout=6)
def verify_ospf6_interface(tgen, topo, dut=None,lan=False, input_dict=None):
"""
This API is to verify ospf routes by running
@@ -1905,7 +1905,7 @@ def verify_ospf6_interface(tgen, topo, dut=None,lan=False, input_dict=None):
return result
-@retry(attempts=11, wait=2, return_is_str=True)
+@retry(retry_timeout=20)
def verify_ospf6_database(tgen, topo, dut, input_dict):
"""
This API is to verify ospf lsa's by running
@@ -2176,9 +2176,9 @@ def config_ospf6_interface (tgen, topo, input_dict=None, build=False,
config_data = []
for lnk in input_dict[router]['links'].keys():
if "ospf6" not in input_dict[router]['links'][lnk]:
- logger.debug("Router %s: ospf6 configs is not present in"
- "input_dict, passed input_dict", router,
- input_dict)
+ logger.debug("Router %s: ospf6 config is not present in"
+ "input_dict, passed input_dict %s", router,
+ str(input_dict))
continue
ospf_data = input_dict[router]['links'][lnk]['ospf6']
data_ospf_area = ospf_data.setdefault("area", None)
diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py
index ce90717fa4..7de1c7a2f9 100644
--- a/tests/topotests/lib/pim.py
+++ b/tests/topotests/lib/pim.py
@@ -495,7 +495,7 @@ def configure_pim_force_expire(tgen, topo, input_dict, build=False):
#############################################
# Verification APIs
#############################################
-@retry(attempts=6, wait=2, return_is_str=True)
+@retry(retry_timeout=12)
def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None, expected=True):
"""
Verify all PIM neighbors are up and running, config is verified
@@ -619,7 +619,7 @@ def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None, expected
return True
-@retry(attempts=21, wait=2, return_is_str=True)
+@retry(retry_timeout=40)
def verify_igmp_groups(tgen, dut, interface, group_addresses, expected=True):
"""
Verify IGMP groups are received from an intended interface
@@ -693,7 +693,7 @@ def verify_igmp_groups(tgen, dut, interface, group_addresses, expected=True):
return True
-@retry(attempts=31, wait=2, return_is_str=True)
+@retry(retry_timeout=60)
def verify_upstream_iif(
tgen, dut, iif, src_address, group_addresses, joinState=None, refCount=1, expected=True
):
@@ -847,7 +847,7 @@ def verify_upstream_iif(
return True
-@retry(attempts=6, wait=2, return_is_str=True)
+@retry(retry_timeout=12)
def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses, expected=True):
"""
Verify join state is updated correctly and join timer is
@@ -966,7 +966,7 @@ def verify_join_state_and_timer(tgen, dut, iif, src_address, group_addresses, ex
return True
-@retry(attempts=41, wait=2, return_is_dict=True)
+@retry(retry_timeout=80)
def verify_ip_mroutes(
tgen, dut, src_address, group_addresses, iif, oil, return_uptime=False, mwait=0, expected=True
):
@@ -1163,7 +1163,7 @@ def verify_ip_mroutes(
return True if return_uptime == False else uptime_dict
-@retry(attempts=31, wait=2, return_is_str=True)
+@retry(retry_timeout=60)
def verify_pim_rp_info(
tgen, topo, dut, group_addresses, oif=None, rp=None, source=None, iamrp=None, expected=True
):
@@ -1320,7 +1320,7 @@ def verify_pim_rp_info(
return True
-@retry(attempts=31, wait=2, return_is_str=True)
+@retry(retry_timeout=60)
def verify_pim_state(
tgen, dut, iif, oil, group_addresses, src_address=None, installed_fl=None, expected=True
):
@@ -1490,7 +1490,7 @@ def verify_pim_interface_traffic(tgen, input_dict):
return output_dict
-@retry(attempts=21, wait=2, return_is_str=True)
+@retry(retry_timeout=40)
def verify_pim_interface(tgen, topo, dut, interface=None, interface_ip=None, expected=True):
"""
Verify all PIM interface are up and running, config is verified
@@ -1797,7 +1797,7 @@ def clear_ip_igmp_interfaces(tgen, dut):
return True
-@retry(attempts=10, wait=2, return_is_str=True)
+@retry(retry_timeout=20)
def clear_ip_mroute_verify(tgen, dut, expected=True):
"""
Clear ip mroute by running "clear ip mroute" cli and verify
@@ -2173,7 +2173,7 @@ def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None):
return rp_details
-@retry(attempts=6, wait=2, return_is_str=True)
+@retry(retry_timeout=12)
def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None, expected=True):
"""
Verify pim rp info by running "show ip pim rp-info" cli
@@ -2276,7 +2276,7 @@ def verify_pim_grp_rp_source(tgen, topo, dut, grp_addr, rp_source, rpadd=None, e
return errormsg
-@retry(attempts=31, wait=2, return_is_str=True)
+@retry(retry_timeout=60)
def verify_pim_bsr(tgen, topo, dut, bsr_ip, expected=True):
"""
Verify all PIM interface are up and running, config is verified
@@ -2332,7 +2332,7 @@ def verify_pim_bsr(tgen, topo, dut, bsr_ip, expected=True):
return True
-@retry(attempts=31, wait=2, return_is_str=True)
+@retry(retry_timeout=60)
def verify_ip_pim_upstream_rpf(tgen, topo, dut, interface, group_addresses, rp=None, expected=True):
"""
Verify IP PIM upstream rpf, config is verified
@@ -2530,7 +2530,7 @@ def enable_disable_pim_bsm(tgen, router, intf, enable=True):
return result
-@retry(attempts=31, wait=2, return_is_str=True)
+@retry(retry_timeout=60)
def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=None, expected=True):
"""
Verify ip pim join by running "show ip pim join" cli
@@ -2621,7 +2621,7 @@ def verify_ip_pim_join(tgen, topo, dut, interface, group_addresses, src_address=
return True
-@retry(attempts=31, wait=2, return_is_dict=True)
+@retry(retry_timeout=60)
def verify_igmp_config(tgen, input_dict, stats_return=False, expected=True):
"""
Verify igmp interface details, verifying following configs:
@@ -2911,7 +2911,7 @@ def verify_igmp_config(tgen, input_dict, stats_return=False, expected=True):
return True if stats_return == False else igmp_stats
-@retry(attempts=31, wait=2, return_is_str=True)
+@retry(retry_timeout=60)
def verify_pim_config(tgen, input_dict, expected=True):
"""
Verify pim interface details, verifying following configs:
@@ -3037,7 +3037,7 @@ def verify_pim_config(tgen, input_dict, expected=True):
return True
-@retry(attempts=21, wait=2, return_is_dict=True)
+@retry(retry_timeout=40)
def verify_multicast_traffic(tgen, input_dict, return_traffic=False, expected=True):
"""
Verify multicast traffic by running
@@ -3280,7 +3280,7 @@ def get_refCount_for_mroute(tgen, dut, iif, src_address, group_addresses):
return refCount
-@retry(attempts=21, wait=2, return_is_str=True)
+@retry(retry_timeout=40)
def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag, expected=True):
"""
Verify flag state for mroutes and make sure (*, G)/(S, G) are having
@@ -3375,7 +3375,7 @@ def verify_multicast_flag_state(tgen, dut, src_address, group_addresses, flag, e
return True
-@retry(attempts=21, wait=2, return_is_str=True)
+@retry(retry_timeout=40)
def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip, expected=True):
"""
Verify all IGMP interface are up and running, config is verified
diff --git a/tests/topotests/msdp_mesh_topo1/r1/pimd.conf b/tests/topotests/msdp_mesh_topo1/r1/pimd.conf
index 49341efa57..30cecee9e1 100644
--- a/tests/topotests/msdp_mesh_topo1/r1/pimd.conf
+++ b/tests/topotests/msdp_mesh_topo1/r1/pimd.conf
@@ -10,6 +10,7 @@ interface r1-eth1
ip igmp
!
ip pim rp 10.254.254.1
+ip msdp timers 10 20 3
ip msdp mesh-group mg-1 source 10.254.254.1
ip msdp mesh-group mg-1 member 10.254.254.2
ip msdp mesh-group mg-1 member 10.254.254.3
diff --git a/tests/topotests/msdp_mesh_topo1/r2/pimd.conf b/tests/topotests/msdp_mesh_topo1/r2/pimd.conf
index 9005263ed7..a51c6d58c7 100644
--- a/tests/topotests/msdp_mesh_topo1/r2/pimd.conf
+++ b/tests/topotests/msdp_mesh_topo1/r2/pimd.conf
@@ -9,6 +9,7 @@ interface r2-eth1
ip pim
!
ip pim rp 10.254.254.2
+ip msdp timers 10 20 3
ip msdp mesh-group mg-1 source 10.254.254.2
ip msdp mesh-group mg-1 member 10.254.254.1
ip msdp mesh-group mg-1 member 10.254.254.3
diff --git a/tests/topotests/msdp_mesh_topo1/r3/pimd.conf b/tests/topotests/msdp_mesh_topo1/r3/pimd.conf
index 30e1148561..663f78620e 100644
--- a/tests/topotests/msdp_mesh_topo1/r3/pimd.conf
+++ b/tests/topotests/msdp_mesh_topo1/r3/pimd.conf
@@ -10,6 +10,7 @@ interface r3-eth1
ip igmp
!
ip pim rp 10.254.254.3
+ip msdp timers 10 20 3
ip msdp mesh-group mg-1 source 10.254.254.3
ip msdp mesh-group mg-1 member 10.254.254.1
ip msdp mesh-group mg-1 member 10.254.254.2
diff --git a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
index 719ead091c..222fb28ade 100644
--- a/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
+++ b/tests/topotests/msdp_mesh_topo1/test_msdp_mesh_topo1.py
@@ -223,7 +223,7 @@ def test_wait_msdp_convergence():
"show ip msdp peer json",
{peer: {"state": "established", "saCount": sa_count}}
)
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=40, wait=2)
assertmsg = '"{}" MSDP connection failure'.format(router)
assert result is None, assertmsg
diff --git a/tests/topotests/msdp_topo1/__init__.py b/tests/topotests/msdp_topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/msdp_topo1/__init__.py
diff --git a/tests/topotests/msdp_topo1/r1/bgpd.conf b/tests/topotests/msdp_topo1/r1/bgpd.conf
new file mode 100644
index 0000000000..01d8ddbdfa
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r1/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.0.2 remote-as 65002
+ neighbor 192.168.1.2 remote-as 65003
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_topo1/r1/pimd.conf b/tests/topotests/msdp_topo1/r1/pimd.conf
new file mode 100644
index 0000000000..fc289031f4
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r1/pimd.conf
@@ -0,0 +1,21 @@
+debug pim
+debug pim zebra
+!
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.1
+!
+interface r1-eth0
+ ip pim
+!
+interface r1-eth1
+ ip pim
+!
+interface r1-eth2
+ ip pim
+ ip igmp
+!
+ip msdp timers 10 20 3
+ip msdp peer 192.168.0.2 source 192.168.0.1
+ip msdp peer 192.168.1.2 source 192.168.1.1
+ip pim rp 10.254.254.1
diff --git a/tests/topotests/msdp_topo1/r1/zebra.conf b/tests/topotests/msdp_topo1/r1/zebra.conf
new file mode 100644
index 0000000000..fb6eabccdf
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r1/zebra.conf
@@ -0,0 +1,14 @@
+ip forwarding
+!
+interface r1-eth0
+ ip address 192.168.0.1/24
+!
+interface r1-eth1
+ ip address 192.168.1.1/24
+!
+interface r1-eth2
+ ip address 192.168.10.1/24
+!
+interface lo
+ ip address 10.254.254.1/32
+!
diff --git a/tests/topotests/msdp_topo1/r2/bgpd.conf b/tests/topotests/msdp_topo1/r2/bgpd.conf
new file mode 100644
index 0000000000..987bef40dd
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r2/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.0.1 remote-as 65001
+ neighbor 192.168.2.2 remote-as 65004
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_topo1/r2/pimd.conf b/tests/topotests/msdp_topo1/r2/pimd.conf
new file mode 100644
index 0000000000..ffa80b12d3
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r2/pimd.conf
@@ -0,0 +1,17 @@
+debug pim
+debug pim zebra
+!
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.2
+!
+interface r2-eth0
+ ip pim
+!
+interface r2-eth1
+ ip pim
+!
+ip msdp timers 10 20 3
+ip msdp peer 192.168.0.1 source 192.168.0.2
+ip msdp peer 192.168.2.2 source 192.168.2.1
+ip pim rp 10.254.254.2
diff --git a/tests/topotests/msdp_topo1/r2/zebra.conf b/tests/topotests/msdp_topo1/r2/zebra.conf
new file mode 100644
index 0000000000..527f7dd766
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r2/zebra.conf
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface r2-eth0
+ ip address 192.168.0.2/24
+!
+interface r2-eth1
+ ip address 192.168.2.1/24
+!
+interface lo
+ ip address 10.254.254.2/32
+!
diff --git a/tests/topotests/msdp_topo1/r3/bgpd.conf b/tests/topotests/msdp_topo1/r3/bgpd.conf
new file mode 100644
index 0000000000..02d685b0e8
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r3/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as 65001
+ neighbor 192.168.3.2 remote-as 65004
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/msdp_topo1/r3/pimd.conf b/tests/topotests/msdp_topo1/r3/pimd.conf
new file mode 100644
index 0000000000..ab12f0573a
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r3/pimd.conf
@@ -0,0 +1,17 @@
+debug pim
+debug pim zebra
+!
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.3
+!
+interface r3-eth0
+ ip pim
+!
+interface r3-eth1
+ ip pim
+!
+ip msdp timers 10 20 3
+ip msdp peer 192.168.1.1 source 192.168.1.2
+ip msdp peer 192.168.3.2 source 192.168.3.1
+ip pim rp 10.254.254.3
diff --git a/tests/topotests/msdp_topo1/r3/zebra.conf b/tests/topotests/msdp_topo1/r3/zebra.conf
new file mode 100644
index 0000000000..688e752f42
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r3/zebra.conf
@@ -0,0 +1,11 @@
+ip forwarding
+!
+interface r3-eth0
+ ip address 192.168.1.2/24
+!
+interface r3-eth1
+ ip address 192.168.3.1/24
+!
+interface lo
+ ip address 10.254.254.3/32
+!
diff --git a/tests/topotests/msdp_topo1/r4/bgpd.conf b/tests/topotests/msdp_topo1/r4/bgpd.conf
new file mode 100644
index 0000000000..633e8db245
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r4/bgpd.conf
@@ -0,0 +1,9 @@
+router bgp 65004
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as 65002
+ neighbor 192.168.3.1 remote-as 65003
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
+
diff --git a/tests/topotests/msdp_topo1/r4/pimd.conf b/tests/topotests/msdp_topo1/r4/pimd.conf
new file mode 100644
index 0000000000..b2e05cb3cb
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r4/pimd.conf
@@ -0,0 +1,21 @@
+debug pim
+debug pim zebra
+!
+interface lo
+ ip pim
+ ip pim use-source 10.254.254.4
+!
+interface r4-eth0
+ ip pim
+!
+interface r4-eth1
+ ip pim
+!
+interface r4-eth2
+ ip pim
+ ip igmp
+!
+ip msdp timers 10 20 3
+ip msdp peer 192.168.2.1 source 192.168.2.2
+ip msdp peer 192.168.3.1 source 192.168.3.2
+ip pim rp 10.254.254.4
diff --git a/tests/topotests/msdp_topo1/r4/zebra.conf b/tests/topotests/msdp_topo1/r4/zebra.conf
new file mode 100644
index 0000000000..1db8132256
--- /dev/null
+++ b/tests/topotests/msdp_topo1/r4/zebra.conf
@@ -0,0 +1,14 @@
+ip forwarding
+!
+interface r4-eth0
+ ip address 192.168.2.2/24
+!
+interface r4-eth1
+ ip address 192.168.3.2/24
+!
+interface r4-eth2
+ ip address 192.168.4.1/24
+!
+interface lo
+ ip address 10.254.254.4/32
+!
diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py
new file mode 100755
index 0000000000..d85e16086d
--- /dev/null
+++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py
@@ -0,0 +1,499 @@
+#!/usr/bin/env python
+
+#
+# test_msdp_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2021 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_msdp_topo1.py: Test the FRR PIM MSDP peer.
+"""
+
+import os
+import sys
+import json
+import socket
+import tempfile
+from functools import partial
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.pimd]
+
+#
+# Test global variables:
+# They are used to handle communicating with external application.
+#
+APP_SOCK_PATH = '/tmp/topotests/apps.sock'
+HELPER_APP_PATH = os.path.join(CWD, "../lib/mcast-tester.py")
+app_listener = None
+app_clients = {}
+
+
+def listen_to_applications():
+ "Start listening socket to connect with applications."
+ # Remove old socket.
+ try:
+ os.unlink(APP_SOCK_PATH)
+ except OSError:
+ pass
+
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM, 0)
+ sock.bind(APP_SOCK_PATH)
+ sock.listen(10)
+ global app_listener
+ app_listener = sock
+
+
+def accept_host(host):
+ "Accept connection from application running in hosts."
+ global app_listener, app_clients
+ conn = app_listener.accept()
+ app_clients[host] = {
+ 'fd': conn[0],
+ 'address': conn[1]
+ }
+
+
+def close_applications():
+ "Signal applications to stop and close all sockets."
+ global app_listener, app_clients
+
+ # Close listening socket.
+ app_listener.close()
+
+ # Remove old socket.
+ try:
+ os.unlink(APP_SOCK_PATH)
+ except OSError:
+ pass
+
+ # Close all host connections.
+ for host in ["h1", "h2"]:
+ if app_clients.get(host) is None:
+ continue
+ app_clients[host]["fd"].close()
+
+
+class MSDPTopo1(Topo):
+ "Test topology builder"
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # Create 4 routers
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["r4"])
+
+ # Create a host connected and direct at r4:
+ tgen.add_host("h1", "192.168.4.100/24", "192.168.4.1")
+ switch.add_link(tgen.gears["h1"])
+
+ # Create a host connected and direct at r1:
+ switch = tgen.add_switch("s6")
+ tgen.add_host("h2", "192.168.10.100/24", "192.168.10.1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["h2"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(MSDPTopo1, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ daemon_file = "{}/{}/zebra.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_ZEBRA, daemon_file)
+
+ daemon_file = "{}/{}/bgpd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_BGP, daemon_file)
+
+ daemon_file = "{}/{}/pimd.conf".format(CWD, rname)
+ if os.path.isfile(daemon_file):
+ router.load_config(TopoRouter.RD_PIM, daemon_file)
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ # Start applications socket.
+ listen_to_applications()
+
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ close_applications()
+ tgen.stop_topology()
+
+
+def test_bgp_convergence():
+ "Wait for BGP protocol convergence"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for protocols to converge")
+
+ def expect_loopback_route(router, iptype, route, proto):
+ "Wait until route is present on RIB for protocol."
+ logger.info("waiting route {} in {}".format(route, router))
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show {} route json".format(iptype),
+ {route: [{"protocol": proto}]},
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = '"{}" convergence failure'.format(router)
+ assert result is None, assertmsg
+
+ # Wait for R1
+ expect_loopback_route("r1", "ip", "10.254.254.2/32", "bgp")
+ expect_loopback_route("r1", "ip", "10.254.254.3/32", "bgp")
+ expect_loopback_route("r1", "ip", "10.254.254.4/32", "bgp")
+
+ # Wait for R2
+ expect_loopback_route("r2", "ip", "10.254.254.1/32", "bgp")
+ expect_loopback_route("r2", "ip", "10.254.254.3/32", "bgp")
+ expect_loopback_route("r2", "ip", "10.254.254.4/32", "bgp")
+
+ # Wait for R3
+ expect_loopback_route("r3", "ip", "10.254.254.1/32", "bgp")
+ expect_loopback_route("r3", "ip", "10.254.254.2/32", "bgp")
+ expect_loopback_route("r3", "ip", "10.254.254.4/32", "bgp")
+
+ # Wait for R4
+ expect_loopback_route("r4", "ip", "10.254.254.1/32", "bgp")
+ expect_loopback_route("r4", "ip", "10.254.254.2/32", "bgp")
+ expect_loopback_route("r4", "ip", "10.254.254.3/32", "bgp")
+
+
+def test_mroute_install():
+ "Test that multicast routes propagated and installed"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.gears["h1"].run("{} '{}' '{}' '{}' &".format(
+ HELPER_APP_PATH, APP_SOCK_PATH, '229.1.2.3', 'h1-eth0'))
+ accept_host("h1")
+
+ tgen.gears["h2"].run("{} --send='0.7' '{}' '{}' '{}' &".format(
+ HELPER_APP_PATH, APP_SOCK_PATH, '229.1.2.3', 'h2-eth0'))
+ accept_host("h2")
+
+ #
+ # Test R1 mroute
+ #
+ expect_1 = {
+ '229.1.2.3': {
+ '192.168.10.100': {
+ 'iif': 'r1-eth2',
+ 'flags': 'SFT',
+ 'oil': {
+ 'r1-eth0': {
+ 'source': '192.168.10.100',
+ 'group': '229.1.2.3'
+ },
+ 'r1-eth1': None
+ }
+ }
+ }
+ }
+ # Create a deep copy of `expect_1`.
+ expect_2 = json.loads(json.dumps(expect_1))
+ # The route will be either via R2 or R3.
+ expect_2['229.1.2.3']['192.168.10.100']['oil']['r1-eth0'] = None
+ expect_2['229.1.2.3']['192.168.10.100']['oil']['r1-eth1'] = {
+ 'source': '192.168.10.100',
+ 'group': '229.1.2.3'
+ }
+
+ def test_r1_mroute():
+ "Test r1 multicast routing table function"
+ out = tgen.gears['r1'].vtysh_cmd('show ip mroute json', isjson=True)
+ if topotest.json_cmp(out, expect_1) is None:
+ return None
+ return topotest.json_cmp(out, expect_2)
+
+ logger.info('Waiting for R1 multicast routes')
+ _, val = topotest.run_and_expect(test_r1_mroute, None, count=55, wait=2)
+ assert val is None, 'multicast route convergence failure'
+
+ #
+ # Test routers 2 and 3.
+ #
+ # NOTE: only one of the paths will get the multicast route.
+ #
+ expect_r2 = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "iif": "r2-eth0",
+ "flags": "S",
+ "oil": {
+ "r2-eth1": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ }
+ }
+ }
+ }
+ }
+ expect_r3 = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "iif": "r3-eth0",
+ "flags": "S",
+ "oil": {
+ "r3-eth1": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ }
+ }
+ }
+ }
+ }
+
+ def test_r2_r3_mroute():
+ "Test r2/r3 multicast routing table function"
+ r2_out = tgen.gears['r2'].vtysh_cmd('show ip mroute json', isjson=True)
+ r3_out = tgen.gears['r3'].vtysh_cmd('show ip mroute json', isjson=True)
+
+ if topotest.json_cmp(r2_out, expect_r2) is not None:
+ return topotest.json_cmp(r3_out, expect_r3)
+
+ return topotest.json_cmp(r2_out, expect_r2)
+
+ logger.info('Waiting for R2 and R3 multicast routes')
+ _, val = topotest.run_and_expect(test_r2_r3_mroute, None, count=55, wait=2)
+ assert val is None, 'multicast route convergence failure'
+
+ #
+ # Test router 4
+ #
+ expect_4 = {
+ "229.1.2.3": {
+ "*": {
+ "iif": "lo",
+ "flags": "SC",
+ "oil": {
+ "pimreg": {
+ "source": "*",
+ "group": "229.1.2.3",
+ "inboundInterface": "lo",
+ "outboundInterface": "pimreg"
+ },
+ "r4-eth2": {
+ "source": "*",
+ "group": "229.1.2.3",
+ "inboundInterface": "lo",
+ "outboundInterface": "r4-eth2"
+ }
+ }
+ },
+ "192.168.10.100": {
+ "iif": "r4-eth0",
+ "flags": "ST",
+ "oil": {
+ "r4-eth2": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ "inboundInterface": "r4-eth0",
+ "outboundInterface": "r4-eth2",
+ }
+ }
+ }
+ }
+ }
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears['r4'], "show ip mroute json", expect_4,
+ )
+ logger.info('Waiting for R4 multicast routes')
+ _, val = topotest.run_and_expect(test_func, None, count=55, wait=2)
+ assert val is None, 'multicast route convergence failure'
+
+
+def test_msdp():
+ """
+ Test MSDP convergence.
+
+ MSDP non meshed groups must propagate the whole SA database (not just
+ their own) to all peers because not all peers talk with each other.
+
+ This setup leads to a potential loop that can be prevented by checking
+ the route's first AS in AS path: it must match the remote eBGP AS number.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1_expect = {
+ "192.168.0.2": {
+ "peer": "192.168.0.2",
+ "local": "192.168.0.1",
+ "state": "established"
+ },
+ "192.168.1.2": {
+ "peer": "192.168.1.2",
+ "local": "192.168.1.1",
+ "state": "established"
+ }
+ }
+ r1_sa_expect = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ "rp": "-",
+ "local": "yes",
+ "sptSetup": "-"
+ }
+ }
+ }
+ r2_expect = {
+ "192.168.0.1": {
+ "peer": "192.168.0.1",
+ "local": "192.168.0.2",
+ "state": "established"
+ },
+ "192.168.2.2": {
+ "peer": "192.168.2.2",
+ "local": "192.168.2.1",
+ "state": "established"
+ }
+ }
+ # Only R2 or R3 will get this SA.
+ r2_r3_sa_expect = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ "rp": "192.168.1.1",
+ "local": "no",
+ "sptSetup": "no",
+ }
+ }
+ }
+ r3_expect = {
+ "192.168.1.1": {
+ "peer": "192.168.1.1",
+ "local": "192.168.1.2",
+ "state": "established"
+ },
+ "192.168.3.2": {
+ "peer": "192.168.3.2",
+ "local": "192.168.3.1",
+ "state": "established"
+ }
+ }
+ r4_expect = {
+ "192.168.2.1": {
+ "peer": "192.168.2.1",
+ "local": "192.168.2.2",
+ "state": "established"
+ },
+ "192.168.3.1": {
+ "peer": "192.168.3.1",
+ "local": "192.168.3.2",
+ "state": "established"
+ }
+ }
+ r4_sa_expect = {
+ "229.1.2.3": {
+ "192.168.10.100": {
+ "source": "192.168.10.100",
+ "group": "229.1.2.3",
+ "rp": "192.168.1.1",
+ "local": "no",
+ "sptSetup": "yes"
+ }
+ }
+ }
+
+ for router in [('r1', r1_expect, r1_sa_expect),
+ ('r2', r2_expect, r2_r3_sa_expect),
+ ('r3', r3_expect, r2_r3_sa_expect),
+ ('r4', r4_expect, r4_sa_expect)]:
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router[0]], "show ip msdp peer json", router[1]
+ )
+ logger.info('Waiting for {} msdp peer data'.format(router[0]))
+ _, val = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert val is None, 'multicast route convergence failure'
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router[0]], "show ip msdp sa json", router[2]
+ )
+ logger.info('Waiting for {} msdp SA data'.format(router[0]))
+ _, val = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert val is None, 'multicast route convergence failure'
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py
index 199746d5f6..60bd6de35d 100644
--- a/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py
+++ b/tests/topotests/multicast_pim_bsm_topo2/test_mcast_pim_bsmp_02.py
@@ -456,7 +456,7 @@ def test_starg_mroute_p0(request):
# Verify mroute not installed
step("Verify mroute not installed in l1")
result = verify_ip_mroutes(
- tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, wait=20, expected=False
+ tgen, dut, src_addr, GROUP_ADDRESS, iif, oil, retry_timeout=20, expected=False
)
assert (
result is not True
@@ -705,6 +705,7 @@ def test_RP_priority_p0(request):
), "Testcase {} :Failed \n Error : rp expected {} rp received {}".format(
tc_name,
rp_add1,
+ rp2[group] if group in rp2 else None
)
# Verify if that rp is installed
diff --git a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
index e55e30270d..b880e0e462 100755
--- a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
+++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py
@@ -526,9 +526,14 @@ def test_multicast_data_traffic_static_RP_send_traffic_then_join_p0(request):
{"dut": "r2", "src_address": source, "iif": "r2-f1-eth0", "oil": "r2-l1-eth2"},
{"dut": "f1", "src_address": source, "iif": "f1-i2-eth1", "oil": "f1-r2-eth3"},
]
+ # On timeout change from default of 80 to 120: failures logs indicate times 90+
+ # seconds for success on the 2nd entry in the above table. Using 100s here restores
+ # previous 80 retries with 2s wait if we assume .5s per vtysh/show ip mroute runtime
+ # (41 * (2 + .5)) == 102.
for data in input_dict:
result = verify_ip_mroutes(
- tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"]
+ tgen, data["dut"], data["src_address"], IGMP_JOIN, data["iif"], data["oil"],
+ retry_timeout=102
)
assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py
index 7bef57b629..d73e8dc9e8 100755
--- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py
+++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py
@@ -424,7 +424,7 @@ def test_add_delete_static_RP_p0(request):
step("r1: Verify show ip igmp group without any IGMP join")
dut = "r1"
interface = "r1-r0-eth0"
- result = verify_igmp_groups(tgen, dut, interface, GROUP_ADDRESS)
+ result = verify_igmp_groups(tgen, dut, interface, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: igmp group present without any IGMP join \n Error: {}".format(
@@ -495,7 +495,7 @@ def test_add_delete_static_RP_p0(request):
step("r1: Verify RP info")
result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
+ tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE, expected=False
)
assert (
result is not True
@@ -504,14 +504,14 @@ def test_add_delete_static_RP_p0(request):
)
step("r1: Verify upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: upstream IIF interface present \n Error: {}".format(tc_name, result)
)
step("r1: Verify upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: upstream join state is up and join timer is running \n Error: {}".format(
@@ -519,14 +519,15 @@ def test_add_delete_static_RP_p0(request):
)
)
+ # 20
step("r1: Verify PIM state")
- result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS)
+ result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False)
assert result is not True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
)
step("r1: Verify ip mroutes")
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert (
result is not True
), "Testcase {} : Failed \n " "r1: mroutes are still present \n Error: {}".format(
@@ -686,7 +687,9 @@ def test_SPT_RPT_path_same_p1(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"r3: (S, G) upstream join state is up and join timer is running\n Error: {}".format(
@@ -819,7 +822,7 @@ def test_not_reachable_static_RP_p0(request):
"r1 : OIL should be same and IIF should be cleared on R1 verify"
"using show ip pim state"
)
- result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS)
+ result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"OIL is not same and IIF is not cleared on R1 \n Error: {}".format(
@@ -828,7 +831,7 @@ def test_not_reachable_static_RP_p0(request):
)
step("r1: upstream IIF should be unknown , verify using show ip pim" "upstream")
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: upstream IIF is not unknown \n Error: {}".format(tc_name, result)
@@ -838,7 +841,7 @@ def test_not_reachable_static_RP_p0(request):
"r1: join state should not be joined and join timer should stop,"
"verify using show ip pim upstream"
)
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: join state is joined and timer is not stopped \n Error: {}".format(
@@ -861,7 +864,7 @@ def test_not_reachable_static_RP_p0(request):
assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
step("r1: (*, G) cleared from mroute table using show ip mroute")
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: (*, G) are not cleared from mroute table \n Error: {}".format(
@@ -932,7 +935,7 @@ def test_add_RP_after_join_received_p1(request):
rp_address = "1.0.2.17"
iif = "r1-r2-eth1"
result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE
+ tgen, TOPO, dut, GROUP_RANGE_ALL, iif, rp_address, SOURCE, expected=False
)
assert (
result is not True
@@ -959,7 +962,7 @@ def test_add_RP_after_join_received_p1(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r1: Verify upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: upstream IFF interface is present \n Error: {}".format(tc_name, result)
@@ -967,7 +970,7 @@ def test_add_RP_after_join_received_p1(request):
step("r1: Verify upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: upstream join state is joined and timer is running \n Error: {}".format(
@@ -976,7 +979,7 @@ def test_add_RP_after_join_received_p1(request):
)
step("r1: Verify PIM state")
- result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS)
+ result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False)
assert (
result is not True
), "Testcase {} : Failed \n " "r1: PIM state is up\n Error: {}".format(
@@ -984,7 +987,7 @@ def test_add_RP_after_join_received_p1(request):
)
step("r1: Verify ip mroutes")
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert (
result is not True
), "Testcase {} : Failed \n " "r1: mroutes are still present\n Error: {}".format(
@@ -1114,14 +1117,14 @@ def test_reachable_static_RP_after_join_p0(request):
step("r1 : Verify upstream IIF interface")
iif = "r1-r2-eth1"
- result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: upstream IIF interface is present\n Error: {}".format(tc_name, result)
)
step("r1 : Verify upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: upstream join state is joined and timer is running\n Error: {}".format(
@@ -1130,7 +1133,7 @@ def test_reachable_static_RP_after_join_p0(request):
)
step("r1 : Verify PIM state")
- result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS)
+ result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS, expected=False)
assert (
result is not True
), "Testcase {} : Failed \n " "r1: PIM state is up\n Error: {}".format(
@@ -1138,7 +1141,7 @@ def test_reachable_static_RP_after_join_p0(request):
)
step("r1 : Verify ip mroutes")
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert (
result is not True
), "Testcase {} : Failed \n " "r1: mroutes are still present\n Error: {}".format(
@@ -1385,7 +1388,9 @@ def test_send_join_on_higher_preffered_rp_p1(request):
step("r1 : Verify rp-info for group 225.1.1.1")
iif = "r1-r4-eth3"
- result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_RANGE, oif, rp_address_2, SOURCE)
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE, oif, rp_address_2, SOURCE, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"r1: rp-info is present for group 225.1.1.1 \n Error: {}".format(
@@ -1643,7 +1648,9 @@ def test_RP_configured_as_LHR_1_p1(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"r3: (S, G) upstream join state is joined and join"
@@ -1850,7 +1857,9 @@ def test_RP_configured_as_LHR_2_p1(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
@@ -2058,7 +2067,9 @@ def test_RP_configured_as_FHR_1_p1(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
@@ -2267,7 +2278,9 @@ def test_RP_configured_as_FHR_2_p2(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
@@ -2394,7 +2407,9 @@ def test_SPT_RPT_path_different_p1(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
@@ -2416,7 +2431,9 @@ def test_SPT_RPT_path_different_p1(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r2: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False
+ )
assert result is not True, (
"Testcase {} : Failed \n "
"r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
@@ -2645,7 +2662,8 @@ def test_restart_pimd_process_p2(request):
assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
step("r3: Verify (S, G) upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS)
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
@@ -2663,6 +2681,7 @@ def test_restart_pimd_process_p2(request):
oil = "r1-r0-eth0"
logger.info("waiting for 10 sec to make sure old mroute time is higher")
sleep(10)
+ # Why do we then wait 60 seconds below before checking the routes?
uptime_before = verify_ip_mroutes(
tgen, dut, STAR, GROUP_ADDRESS, iif, oil, return_uptime=True, mwait=60
)
@@ -2679,6 +2698,7 @@ def test_restart_pimd_process_p2(request):
logger.info("Waiting for 5sec to get PIMd restarted and mroute" " re-learned..")
sleep(5)
+ # Why do we then wait 10 seconds below before checking the routes?
uptime_after = verify_ip_mroutes(
tgen, dut, STAR, GROUP_ADDRESS, iif, oil, return_uptime=True, mwait=10
)
@@ -2814,7 +2834,7 @@ def test_multiple_groups_same_RP_address_p2(request):
step("r3: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -2838,7 +2858,7 @@ def test_multiple_groups_same_RP_address_p2(request):
step("r2: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -2959,7 +2979,7 @@ def test_multiple_groups_same_RP_address_p2(request):
step("r2: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -2981,7 +3001,7 @@ def test_multiple_groups_same_RP_address_p2(request):
step("r3: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, group_address_list
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -3163,7 +3183,7 @@ def test_multiple_groups_different_RP_address_p2(request):
step("r2: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -3187,7 +3207,7 @@ def test_multiple_groups_different_RP_address_p2(request):
step("r3: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -3259,7 +3279,7 @@ def test_multiple_groups_different_RP_address_p2(request):
step("r4: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -3283,7 +3303,7 @@ def test_multiple_groups_different_RP_address_p2(request):
step("r3: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
)
assert result is not True, "Testcase {} :Failed \n Error: {}".format(
tc_name, result
@@ -3436,7 +3456,7 @@ def test_multiple_groups_different_RP_address_p2(request):
step("r2: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -3460,7 +3480,7 @@ def test_multiple_groups_different_RP_address_p2(request):
step("r3: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -3532,7 +3552,7 @@ def test_multiple_groups_different_RP_address_p2(request):
step("r4: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -3556,7 +3576,7 @@ def test_multiple_groups_different_RP_address_p2(request):
step("r3: Verify (S, G) upstream join state and join timer")
result = verify_join_state_and_timer(
- tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
@@ -3682,14 +3702,14 @@ def test_shutdown_primary_path_p1(request):
step(
"Verify after shut of R1 to R3 link , verify (*,G) entries got"
- "cleared from all the node R1, R2, R3"
+ " cleared from all the node R1, R2, R3"
)
step("r1: Verify (*, G) ip mroutes")
dut = "r1"
iif = "r1-r3-eth2"
oif = "r1-r0-eth0"
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
@@ -3701,7 +3721,7 @@ def test_shutdown_primary_path_p1(request):
dut = "r2"
iif = "lo"
oif = "r2-r3-eth1"
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r2: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
@@ -3713,7 +3733,7 @@ def test_shutdown_primary_path_p1(request):
dut = "r3"
iif = "r3-r2-eth1"
oif = "r3-r1-eth0"
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r3: (*,G) mroutes are not cleared after shut of R1 to R3 link\n Error: {}".format(
@@ -3878,7 +3898,7 @@ def test_delete_RP_shut_noshut_upstream_interface_p1(request):
dut = "r1"
iif = "r1-r2-eth1"
oif = "r1-r0-eth0"
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format(
@@ -3890,7 +3910,7 @@ def test_delete_RP_shut_noshut_upstream_interface_p1(request):
dut = "r2"
iif = "lo"
oif = "r2-r1-eth0"
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r2: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format(
@@ -4005,7 +4025,7 @@ def test_delete_RP_shut_noshut_RP_interface_p1(request):
dut = "r1"
iif = "r1-r2-eth1"
oif = "r1-r0-eth0"
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r1: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format(
@@ -4017,7 +4037,7 @@ def test_delete_RP_shut_noshut_RP_interface_p1(request):
dut = "r2"
iif = "lo"
oif = "r2-r1-eth0"
- result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif)
+ result = verify_ip_mroutes(tgen, dut, STAR, GROUP_ADDRESS, iif, oif, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
"r2: (*,G) mroutes are not cleared after shut of R1 to R2 and R3 link\n Error: {}".format(
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
index 9c3be58937..a7f2893eab 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py
@@ -257,7 +257,7 @@ def test_ospf_authentication_simple_pass_tc28_p1(request):
sleep(6)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(
- tgen, topo, dut=dut, expected=False, attempts=5
+ tgen, topo, dut=dut, expected=False, retry_timeout=10
)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
@@ -395,7 +395,7 @@ def test_ospf_authentication_md5_tc29_p1(request):
sleep(6)
dut = "r1"
ospf_covergence = verify_ospf_neighbor(
- tgen, topo, dut=dut, expected=False, attempts=3
+ tgen, topo, dut=dut, expected=False, retry_timeout=6
)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
@@ -460,7 +460,7 @@ def test_ospf_authentication_md5_tc29_p1(request):
sleep(6)
dut = "r2"
ospf_covergence = verify_ospf_neighbor(
- tgen, topo, dut=dut, expected=False, attempts=5
+ tgen, topo, dut=dut, expected=False, retry_timeout=10
)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
@@ -610,7 +610,7 @@ def test_ospf_authentication_different_auths_tc30_p1(request):
step("Verify that the neighbour is not FULL between R1 and R2.")
dut = "r1"
ospf_covergence = verify_ospf_neighbor(
- tgen, topo, dut=dut, expected=False, attempts=5
+ tgen, topo, dut=dut, expected=False, retry_timeout=10
)
assert ospf_covergence is not True, "setup_module :Failed \n Error:" " {}".format(
ospf_covergence
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
index 1aabc06db0..49ecaac9f7 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py
@@ -326,7 +326,7 @@ def test_ospf_ecmp_tc16_p0(request):
step("Verify that route is withdrawn from R2.")
dut = "r1"
result = verify_ospf_rib(
- tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
+ tgen, dut, input_dict, next_hop=nh, retry_timeout=10, expected=False
)
assert (
result is not True
@@ -342,7 +342,7 @@ def test_ospf_ecmp_tc16_p0(request):
input_dict,
protocol=protocol,
next_hop=nh,
- attempts=5,
+ retry_timeout=10,
expected=False,
)
assert (
@@ -434,7 +434,7 @@ def test_ospf_ecmp_tc17_p0(request):
step("Verify that route is withdrawn from R2.")
dut = "r1"
result = verify_ospf_rib(
- tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
+ tgen, dut, input_dict, next_hop=nh, retry_timeout=10, expected=False
)
assert (
result is not True
@@ -450,7 +450,7 @@ def test_ospf_ecmp_tc17_p0(request):
input_dict,
protocol=protocol,
next_hop=nh,
- attempts=5,
+ retry_timeout=10,
expected=False,
)
assert (
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
index e6dc18a434..47c6c45e39 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp_lan.py
@@ -305,7 +305,7 @@ def test_ospf_lan_ecmp_tc18_p0(request):
step("Verify that all the routes are withdrawn from R0")
dut = "r1"
result = verify_ospf_rib(
- tgen, dut, input_dict, next_hop=nh, attempts=5, expected=False
+ tgen, dut, input_dict, next_hop=nh, retry_timeout=10, expected=False
)
assert (
result is not True
@@ -321,7 +321,7 @@ def test_ospf_lan_ecmp_tc18_p0(request):
input_dict,
protocol=protocol,
next_hop=nh,
- attempts=5,
+ retry_timeout=10,
expected=False,
)
assert (
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
index 7864d0307a..0848f6c94a 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py
@@ -501,7 +501,7 @@ def test_ospf_routemaps_functionality_tc20_p0(request):
dut = "r1"
protocol = "ospf"
- result = verify_ospf_rib(tgen, dut, input_dict, attempts=2, expected=False)
+ result = verify_ospf_rib(tgen, dut, input_dict, retry_timeout=4, expected=False)
assert (
result is not True
), "Testcase {} : Failed \n " "r1: OSPF routes are present \n Error: {}".format(
@@ -509,7 +509,7 @@ def test_ospf_routemaps_functionality_tc20_p0(request):
)
result = verify_rib(
- tgen, "ipv4", dut, input_dict, protocol=protocol, attempts=2, expected=False
+ tgen, "ipv4", dut, input_dict, protocol=protocol, retry_timeout=4, expected=False
)
assert (
result is not True
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 9dfde325f6..f17346d5b1 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py
@@ -263,7 +263,7 @@ def test_ospf_redistribution_tc5_p0(request):
input_dict,
protocol=protocol,
next_hop=nh,
- attempts=5,
+ retry_timeout=10,
expected=False,
)
assert result is not True, (
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
index bbb4370a93..2c44ec2351 100644
--- 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
@@ -690,9 +690,8 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ebgp(request):
next_hop=nh,
protocol=protocol,
fib=True,
+ retry_timeout=6,
expected=False,
- wait=2,
- attempts=3,
)
assert (
result is not True
@@ -804,8 +803,7 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ebgp(request):
protocol=protocol,
fib=True,
expected=False,
- wait=2,
- attempts=3,
+ retry_timeout=6,
)
assert (
result is not True
@@ -1283,8 +1281,7 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ebgp(request):
protocol=protocol,
fib=True,
expected=False,
- wait=2,
- attempts=3,
+ retry_timeout=6,
)
assert (
result is not True
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
index ee0e01b411..85b9e8b543 100644
--- 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
@@ -695,12 +695,11 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request):
protocol=protocol,
fib=True,
expected=False,
- wait=2,
- attempts=3,
+ retry_timeout=6,
)
assert (
result is not True
- ), "Testcase {} : Failed \nError: Routes " " are missing in RIB".format(tc_name)
+ ), "Testcase {} : Failed \nError: Routes " " are present in RIB".format(tc_name)
step(
"Remove the static route configured with nexthop N1 to N8, one"
@@ -808,8 +807,7 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc6_ibgp(request):
protocol=protocol,
fib=True,
expected=False,
- wait=2,
- attempts=3,
+ retry_timeout=6,
)
assert (
result is not True
@@ -1512,8 +1510,7 @@ def test_static_route_8nh_diff_AD_bgp_ecmp_p1_tc10_ibgp(request):
protocol=protocol,
fib=True,
expected=False,
- wait=2,
- attempts=3,
+ retry_timeout=6,
)
assert (
result is not True