summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/topotests/bfd_vrflite_topo1/__init__.py0
-rw-r--r--tests/topotests/bfd_vrflite_topo1/r1/bfd_peers_status.json96
-rw-r--r--tests/topotests/bfd_vrflite_topo1/r1/bfdd.conf26
-rw-r--r--tests/topotests/bfd_vrflite_topo1/r1/zebra.conf24
-rw-r--r--tests/topotests/bfd_vrflite_topo1/r2/bfdd.conf26
-rw-r--r--tests/topotests/bfd_vrflite_topo1/r2/zebra.conf24
-rw-r--r--tests/topotests/bfd_vrflite_topo1/test_bfd_vrflite_topo1.py153
-rw-r--r--tests/topotests/bgp_as_override/__init__.py0
-rw-r--r--tests/topotests/bgp_as_override/r1/bgpd.conf10
-rw-r--r--tests/topotests/bgp_as_override/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_as_override/r2/bgpd.conf10
-rw-r--r--tests/topotests/bgp_as_override/r2/zebra.conf9
-rw-r--r--tests/topotests/bgp_as_override/r3/bgpd.conf13
-rw-r--r--tests/topotests/bgp_as_override/r3/zebra.conf9
-rw-r--r--tests/topotests/bgp_as_override/r4/bgpd.conf7
-rw-r--r--tests/topotests/bgp_as_override/r4/zebra.conf6
-rw-r--r--tests/topotests/bgp_as_override/test_bgp_as_override.py122
-rw-r--r--tests/topotests/bgp_default_originate/bgp_default_originate_2links.json136
-rw-r--r--tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py1414
-rw-r--r--tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py2
-rw-r--r--tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py2
-rw-r--r--tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py3
-rw-r--r--tests/topotests/bgp_default_originate/test_default_orginate_vrf.py2
-rw-r--r--tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py2
-rw-r--r--tests/topotests/bgp_default_route_route_map_match/r1/zebra.conf2
-rw-r--r--tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_ibgp_nbr.py3
-rw-r--r--tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_nbr.py2
-rw-r--r--tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py2
-rw-r--r--tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_nbr.py3
-rw-r--r--tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_unnumbered_nbr.py1
-rwxr-xr-xtests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py13
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/__init__.py0
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/bgpd.conf24
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes.json69
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes_unfiltered.json94
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf14
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/zebra.conf13
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r2/bgpd.conf35
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf14
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r2/zebra.conf16
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py201
-rw-r--r--tests/topotests/lib/common_config.py90
-rw-r--r--tests/topotests/lib/micronet.py54
-rw-r--r--tests/topotests/lib/pim.py439
-rw-r--r--tests/topotests/lib/topogen.py6
-rw-r--r--tests/topotests/lib/topojson.py11
-rw-r--r--tests/topotests/lib/topotest.py1
-rw-r--r--tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json197
-rwxr-xr-xtests/topotests/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py414
-rw-r--r--tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py2
-rw-r--r--tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py2
-rw-r--r--tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py2
-rw-r--r--tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py1
53 files changed, 3729 insertions, 101 deletions
diff --git a/tests/topotests/bfd_vrflite_topo1/__init__.py b/tests/topotests/bfd_vrflite_topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bfd_vrflite_topo1/__init__.py
diff --git a/tests/topotests/bfd_vrflite_topo1/r1/bfd_peers_status.json b/tests/topotests/bfd_vrflite_topo1/r1/bfd_peers_status.json
new file mode 100644
index 0000000000..07e96d74bd
--- /dev/null
+++ b/tests/topotests/bfd_vrflite_topo1/r1/bfd_peers_status.json
@@ -0,0 +1,96 @@
+[
+ {
+ "multihop":false,
+ "peer":"192.168.0.2",
+ "vrf":"vrf1",
+ "passive-mode":false,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ },
+ {
+ "multihop":true,
+ "peer":"192.0.2.2",
+ "local":"192.0.2.1",
+ "vrf":"vrf2",
+ "passive-mode":false,
+ "minimum-ttl":254,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ },
+ {
+ "multihop":false,
+ "peer":"192.168.0.2",
+ "vrf":"vrf2",
+ "passive-mode":false,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ },
+ {
+ "multihop":false,
+ "peer":"192.168.0.2",
+ "vrf":"default",
+ "passive-mode":false,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ },
+ {
+ "multihop":true,
+ "peer":"192.0.2.2",
+ "local":"192.0.2.1",
+ "vrf":"vrf1",
+ "passive-mode":false,
+ "minimum-ttl":254,
+ "status":"up",
+ "diagnostic":"ok",
+ "remote-diagnostic":"ok",
+ "receive-interval":1000,
+ "transmit-interval":1000,
+ "echo-receive-interval":50,
+ "echo-transmit-interval":0,
+ "detect-multiplier":3,
+ "remote-receive-interval":1000,
+ "remote-transmit-interval":1000,
+ "remote-echo-receive-interval":50,
+ "remote-detect-multiplier":3
+ }
+]
diff --git a/tests/topotests/bfd_vrflite_topo1/r1/bfdd.conf b/tests/topotests/bfd_vrflite_topo1/r1/bfdd.conf
new file mode 100644
index 0000000000..96e8ff4b12
--- /dev/null
+++ b/tests/topotests/bfd_vrflite_topo1/r1/bfdd.conf
@@ -0,0 +1,26 @@
+!
+! debug bfd network
+! debug bfd peer
+! debug bfd zebra
+!
+bfd
+ peer 192.168.0.2 vrf vrf1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.168.0.2 vrf vrf2
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.168.0.2
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.0.2.2 multihop local-address 192.0.2.1 vrf vrf1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.0.2.2 multihop local-address 192.0.2.1 vrf vrf2
+ transmit-interval 1000
+ receive-interval 1000
+ ! \ No newline at end of file
diff --git a/tests/topotests/bfd_vrflite_topo1/r1/zebra.conf b/tests/topotests/bfd_vrflite_topo1/r1/zebra.conf
new file mode 100644
index 0000000000..ebb4e63be7
--- /dev/null
+++ b/tests/topotests/bfd_vrflite_topo1/r1/zebra.conf
@@ -0,0 +1,24 @@
+vrf vrf1
+ ip route 192.0.2.2/32 192.168.0.2
+!
+vrf vrf2
+ ip route 192.0.2.2/32 192.168.0.2
+!
+interface r1-eth0 vrf vrf3
+ ip address 192.168.0.1/24
+!
+interface r1-eth0.100 vrf vrf1
+ ip address 192.168.0.1/24
+!
+interface r1-eth0.200 vrf vrf2
+ ip address 192.168.0.1/24
+!
+interface r1-eth0.300
+ ip address 192.168.0.1/24
+!
+interface r1-loop1 vrf vrf1
+ ip address 192.0.2.1/32
+!
+interface r1-loop2 vrf vrf2
+ ip address 192.0.2.1/32
+! \ No newline at end of file
diff --git a/tests/topotests/bfd_vrflite_topo1/r2/bfdd.conf b/tests/topotests/bfd_vrflite_topo1/r2/bfdd.conf
new file mode 100644
index 0000000000..7b11a4785a
--- /dev/null
+++ b/tests/topotests/bfd_vrflite_topo1/r2/bfdd.conf
@@ -0,0 +1,26 @@
+!
+! debug bfd network
+! debug bfd peer
+! debug bfd zebra
+!
+bfd
+ peer 192.168.0.1 vrf vrf1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.168.0.1 vrf vrf2
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.168.0.1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.0.2.1 multihop local-address 192.0.2.2 vrf vrf1
+ transmit-interval 1000
+ receive-interval 1000
+ !
+ peer 192.0.2.1 multihop local-address 192.0.2.2 vrf vrf2
+ transmit-interval 1000
+ receive-interval 1000
+ ! \ No newline at end of file
diff --git a/tests/topotests/bfd_vrflite_topo1/r2/zebra.conf b/tests/topotests/bfd_vrflite_topo1/r2/zebra.conf
new file mode 100644
index 0000000000..d8b996e9ed
--- /dev/null
+++ b/tests/topotests/bfd_vrflite_topo1/r2/zebra.conf
@@ -0,0 +1,24 @@
+vrf vrf1
+ ip route 192.0.2.1/32 192.168.0.1
+!
+vrf vrf2
+ ip route 192.0.2.1/32 192.168.0.1
+!
+interface r2-eth0 vrf vrf3
+ ip address 192.168.0.2/24
+!
+interface r2-eth0.100 vrf vrf1
+ ip address 192.168.0.2/24
+!
+interface r2-eth0.200 vrf vrf2
+ ip address 192.168.0.2/24
+!
+interface r2-eth0.300
+ ip address 192.168.0.2/24
+!
+interface r2-loop1 vrf vrf1
+ ip address 192.0.2.2/32
+!
+interface r2-loop2 vrf vrf2
+ ip address 192.0.2.2/32
+! \ No newline at end of file
diff --git a/tests/topotests/bfd_vrflite_topo1/test_bfd_vrflite_topo1.py b/tests/topotests/bfd_vrflite_topo1/test_bfd_vrflite_topo1.py
new file mode 100644
index 0000000000..b7afb8e3b9
--- /dev/null
+++ b/tests/topotests/bfd_vrflite_topo1/test_bfd_vrflite_topo1.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python
+
+#
+# test_bfd_vrflite_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2018 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+# Copyright (c) 2022 by 6WIND
+#
+# 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_bfd_vrflite_topo1.py: Test the FRR BFD daemon.
+"""
+
+import os
+import sys
+import json
+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.
+
+pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ # Create 2 routers
+ for routern in range(1, 3):
+ 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["r2"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r1"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ logger.info("Testing with Linux VRF support and udp_l3mdev=0")
+ if os.system("echo 0 > /proc/sys/net/ipv4/udp_l3mdev_accept") != 0:
+ return pytest.skip(
+ "Skipping BFD vrflite Topo1 Test. Linux VRF not available on System"
+ )
+
+ for rname, router in router_list.items():
+ router.net.add_l3vrf("vrf1", 10)
+ router.net.add_l3vrf("vrf2", 20)
+ router.net.add_l3vrf("vrf3", 30)
+ router.net.add_vlan(rname + "-eth0.100", rname + "-eth0", 100)
+ router.net.add_vlan(rname + "-eth0.200", rname + "-eth0", 200)
+ router.net.add_vlan(rname + "-eth0.300", rname + "-eth0", 300)
+ router.net.attach_iface_to_l3vrf(rname + "-eth0.100", "vrf1")
+ router.net.attach_iface_to_l3vrf(rname + "-eth0.200", "vrf2")
+ router.net.add_loop(rname + "-loop1")
+ router.net.add_loop(rname + "-loop2")
+ router.net.attach_iface_to_l3vrf(rname + "-loop1", "vrf1")
+ router.net.attach_iface_to_l3vrf(rname + "-loop2", "vrf2")
+ router.net.attach_iface_to_l3vrf(rname + "-eth0", "vrf3")
+
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # Move interfaces out of vrf namespace and delete the namespace
+ router_list = tgen.routers()
+ for rname, router in router_list.items():
+ router.net.del_iface(rname + "-eth0.100")
+ router.net.del_iface(rname + "-eth0.200")
+ router.net.del_iface(rname + "-eth0.300")
+ router.net.del_iface(rname + "-loop1")
+ router.net.del_iface(rname + "-loop2")
+
+ tgen.stop_topology()
+
+
+def test_bfd_connection():
+ "Assert that the BFD peers can find themselves."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ logger.info("waiting for bfd peers to go up")
+ router = tgen.gears['r1']
+ json_file = "{}/{}/bfd_peers_status.json".format(CWD, 'r1')
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(
+ topotest.router_json_cmp, router, "show bfd peers json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=16, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_as_override/__init__.py b/tests/topotests/bgp_as_override/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_as_override/__init__.py
diff --git a/tests/topotests/bgp_as_override/r1/bgpd.conf b/tests/topotests/bgp_as_override/r1/bgpd.conf
new file mode 100644
index 0000000000..3cfb7a2c90
--- /dev/null
+++ b/tests/topotests/bgp_as_override/r1/bgpd.conf
@@ -0,0 +1,10 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_as_override/r1/zebra.conf b/tests/topotests/bgp_as_override/r1/zebra.conf
new file mode 100644
index 0000000000..63728eb5d5
--- /dev/null
+++ b/tests/topotests/bgp_as_override/r1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface r1-eth0
+ ip address 192.168.1.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_as_override/r2/bgpd.conf b/tests/topotests/bgp_as_override/r2/bgpd.conf
new file mode 100644
index 0000000000..5e3b0c7f87
--- /dev/null
+++ b/tests/topotests/bgp_as_override/r2/bgpd.conf
@@ -0,0 +1,10 @@
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers 1 3
+ neighbor 192.168.2.2 timers connect 1
+!
diff --git a/tests/topotests/bgp_as_override/r2/zebra.conf b/tests/topotests/bgp_as_override/r2/zebra.conf
new file mode 100644
index 0000000000..5bdfd02224
--- /dev/null
+++ b/tests/topotests/bgp_as_override/r2/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface r2-eth0
+ ip address 192.168.1.1/30
+!
+interface r2-eth1
+ ip address 192.168.2.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_as_override/r3/bgpd.conf b/tests/topotests/bgp_as_override/r3/bgpd.conf
new file mode 100644
index 0000000000..6bbe56b678
--- /dev/null
+++ b/tests/topotests/bgp_as_override/r3/bgpd.conf
@@ -0,0 +1,13 @@
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+ neighbor 192.168.3.1 remote-as external
+ neighbor 192.168.3.1 timers 1 3
+ neighbor 192.168.3.1 timers connect 1
+ address-family ipv4 unicast
+ neighbor 192.168.3.1 as-override
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_as_override/r3/zebra.conf b/tests/topotests/bgp_as_override/r3/zebra.conf
new file mode 100644
index 0000000000..77782be3a8
--- /dev/null
+++ b/tests/topotests/bgp_as_override/r3/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface r3-eth0
+ ip address 192.168.2.2/30
+!
+interface r3-eth1
+ ip address 192.168.3.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_as_override/r4/bgpd.conf b/tests/topotests/bgp_as_override/r4/bgpd.conf
new file mode 100644
index 0000000000..1bdee0800a
--- /dev/null
+++ b/tests/topotests/bgp_as_override/r4/bgpd.conf
@@ -0,0 +1,7 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.3.2 remote-as external
+ neighbor 192.168.3.2 timers 1 3
+ neighbor 192.168.3.2 timers connect 1
+!
diff --git a/tests/topotests/bgp_as_override/r4/zebra.conf b/tests/topotests/bgp_as_override/r4/zebra.conf
new file mode 100644
index 0000000000..71dc595558
--- /dev/null
+++ b/tests/topotests/bgp_as_override/r4/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r4-eth0
+ ip address 192.168.3.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_as_override/test_bgp_as_override.py b/tests/topotests/bgp_as_override/test_bgp_as_override.py
new file mode 100644
index 0000000000..40085cd7ec
--- /dev/null
+++ b/tests/topotests/bgp_as_override/test_bgp_as_override.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 7):
+ 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["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r4"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_as_override():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r3 = tgen.gears["r3"]
+ r4 = tgen.gears["r4"]
+
+ def _bgp_converge():
+ output = json.loads(r3.vtysh_cmd("show ip bgp neighbor 192.168.2.1 json"))
+ expected = {
+ "192.168.2.1": {
+ "bgpState": "Established",
+ "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}},
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_as_override():
+ output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "172.16.255.1/32": [{"valid": True, "path": "65003 65002 65003"}]
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ step("Initial BGP converge")
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see BGP convergence on R4"
+
+ step("Check if BGP as-override from R3 works")
+ test_func = functools.partial(_bgp_as_override)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Failed to see overriden ASN (65001) from R3"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_default_originate/bgp_default_originate_2links.json b/tests/topotests/bgp_default_originate/bgp_default_originate_2links.json
new file mode 100644
index 0000000000..9e98235a2e
--- /dev/null
+++ b/tests/topotests/bgp_default_originate/bgp_default_originate_2links.json
@@ -0,0 +1,136 @@
+{
+ "address_types": ["ipv4", "ipv6"],
+ "ipv4base": "192.168.0.0",
+ "ipv4mask": 3024,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "192.168.0.0",
+ "v4mask": 24,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
+ "routers": {
+ "r0": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"neighbor": {"r1": {"dest_link": {"r0": {}}}}}
+ },
+ "ipv6": {
+ "unicast": {"neighbor": {"r1": {"dest_link": {"r0": {}}}}}
+ }
+ }
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r0": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r0": {"dest_link": {"r1": {}}},
+ "r2": {"dest_link": {"r1-link1": {}, "r1-link2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r0": {"dest_link": {"r1": {}}},
+ "r2": {"dest_link": {"r1-link1": {}, "r1-link2": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2-link1": {}, "r2-link2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2-link1": {}, "r2-link2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "500",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"neighbor": {"r3": {"dest_link": {"r4": {}}}}}
+ },
+ "ipv6": {
+ "unicast": {"neighbor": {"r3": {"dest_link": {"r4": {}}}}}
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py
new file mode 100644
index 0000000000..c8cdc7ec5c
--- /dev/null
+++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py
@@ -0,0 +1,1414 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF")
+# in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+# Shreenidhi A R <rshreenidhi@vmware.com>
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+"""
+Following tests are covered.
+1. Verify default-originate route with default static and network command
+2. Verify default-originate route with aggregate summary command
+"""
+import os
+import sys
+import time
+import pytest
+import datetime
+from copy import deepcopy
+from lib.topolog import logger
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topojson import build_config_from_json
+from lib.topolog import logger
+
+from lib.bgp import (
+ verify_bgp_convergence,
+ create_router_bgp,
+ verify_bgp_rib,
+ get_dut_as_number,
+ verify_rib_default_route,
+ verify_fib_default_route,
+)
+from lib.common_config import (
+ verify_fib_routes,
+ step,
+ run_frr_cmd,
+ get_frr_ipv6_linklocal,
+ start_topology,
+ apply_raw_config,
+ write_test_header,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_static_routes,
+ check_router_status,
+)
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+
+# Global variables
+topo = None
+NETWORK1_1 = {"ipv4": "198.51.1.1/32", "ipv6": "2001:DB8::1:1/128"}
+NETWORK1_2 = {"ipv4": "198.51.1.2/32", "ipv6": "2001:DB8::1:2/128"}
+NETWORK1_3 = {"ipv4": "198.51.1.3/32", "ipv6": "2001:DB8::1:3/128"}
+NETWORK1_4 = {"ipv4": "198.51.1.4/32", "ipv6": "2001:DB8::1:4/128"}
+NETWORK1_5 = {"ipv4": "198.51.1.5/32", "ipv6": "2001:DB8::1:5/128"}
+
+ipv4_uptime_dict = {
+ "r2": {
+ "static_routes": [
+ {"network": "0.0.0.0/0"},
+ ]
+ }
+}
+
+ipv6_uptime_dict = {
+ "r2": {
+ "static_routes": [
+ {"network": "::/0"},
+ ]
+ }
+}
+
+DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/bgp_default_originate_2links.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global ADDR_TYPES
+ global BGP_CONVERGENCE
+ global DEFAULT_ROUTES
+ global DEFAULT_ROUTE_NXT_HOP_LINK1, DEFAULT_ROUTE_NXT_HOP_LINK2
+ ADDR_TYPES = check_address_types()
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+
+ interface = topo["routers"]["r1"]["links"]["r2-link1"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r1", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_LINK1 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+
+ interface = topo["routers"]["r1"]["links"]["r2-link2"]["interface"]
+ ipv6_link_local = get_frr_ipv6_linklocal(tgen, "r1", intf=interface)
+ ipv4_nxt_hop = topo["routers"]["r1"]["links"]["r2-link2"]["ipv4"].split("/")[0]
+ ipv6_nxt_hop = topo["routers"]["r1"]["links"]["r2-link2"]["ipv6"].split("/")[0]
+ DEFAULT_ROUTE_NXT_HOP_LINK2 = {"ipv4": ipv4_nxt_hop, "ipv6": ipv6_link_local}
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Local API's
+#
+#####################################################
+
+
+def get_rib_route_uptime(tgen, addr_type, dut, input_dict):
+ """
+ Verify route uptime in RIB using "show ip route"
+
+ Parameters
+ ----------
+ * `tgen` : topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test, for which user wants to test the data
+ * `input_dict` : input dict, has details of static routes
+ * `route_uptime`: uptime of the routes
+
+ Usage
+ -----
+ # Creating static routes for r1
+ input_dict_r1 = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": "147.10.13.4/32"
+ },
+ {
+ "network": "147.10.12.0/24"
+ },
+ {
+ "network": "147.10.13.4/32"
+ },
+ {
+ "network": "147.10.13.4/32"
+ },
+ {
+ "network": "147.10.13.4/32"
+ }
+ ]
+ }
+ }
+
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.info("Entering lib API: get_rib_route_uptime()")
+ route_time = []
+ out_route_dict = {}
+ router_list = tgen.routers()
+ for routerInput in input_dict.keys():
+ for router, rnode in router_list.items():
+ if router != dut:
+ continue
+
+ logger.info("Checking router %s RIB:", router)
+
+ # Verifying RIB routes
+ if addr_type == "ipv4":
+ command = "show ip route"
+ else:
+ command = "show ipv6 route"
+
+ if "static_routes" in input_dict[routerInput]:
+ static_routes = input_dict[routerInput]["static_routes"]
+
+ for static_route in static_routes:
+ if "vrf" in static_route and static_route["vrf"] is not None:
+
+ logger.info(
+ "[DUT: {}]: Verifying routes for VRF:"
+ " {}".format(router, static_route["vrf"])
+ )
+ cmd = "{} vrf {}".format(command, static_route["vrf"])
+
+ else:
+ cmd = "{}".format(command)
+
+ cmd = "{} json".format(cmd)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ if bool(rib_routes_json) is False:
+ errormsg = "No route found in rib of router {}..".format(router)
+ return errormsg
+ network = static_route["network"]
+ route_time.append(rib_routes_json[network][0]["uptime"])
+
+ logger.info("Exiting lib API: get_rib_route_uptime()")
+ return route_time
+
+
+def verify_the_uptime(time_stamp_before, time_stamp_after, incremented=None):
+ """
+ time_stamp_before : string the time stamp captured
+ time_stamp_after : string the time stamp captured
+ """
+ uptime_before = datetime.datetime.strptime(time_stamp_before[0], "%H:%M:%S")
+ uptime_after = datetime.datetime.strptime(time_stamp_after[0], "%H:%M:%S")
+
+ if incremented == True:
+ if uptime_before < uptime_after:
+ logger.info(
+ " The Uptime [{}] is incremented than [{}].......PASSED ".format(
+ time_stamp_before, time_stamp_after
+ )
+ )
+ return True
+ else:
+ logger.error(
+ " The Uptime [{}] is expected to be incremented than [{}].......FAILED ".format(
+ time_stamp_before, time_stamp_after
+ )
+ )
+ return False
+ else:
+ logger.info(
+ " The Uptime [{}] is not incremented than [{}] ".format(
+ time_stamp_before, time_stamp_after
+ )
+ )
+ return True
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_verify_bgp_default_originate_with_default_static_route_p1(request):
+ """
+ Summary: "Verify default-originate route with default static and network command "
+
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE, DEFAULT_ROUTE_NXT_HOP_LINK1, DEFAULT_ROUTE_NXT_HOP_LINK2, DEFAULT_ROUTES
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure 2 link between R1 and R2")
+ step("Configure IPV4 and IPV6 EBGP between R1 and R2 both the links")
+ step("Configure default-originate on R1 IPv4 and IPv6 BGP session link-1 only ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {"r2": {"dest-link": "r1-link1"}}
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {"r2": {"dest-link": "r1-link1"}}
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify IPv4/IPv6 default originate routes present on R2 nexthop as link-1")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "next_hop": DEFAULT_ROUTE_NXT_HOP_LINK1[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_fib_routes(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_LINK1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(
+ tgen,
+ addr_type,
+ "r2",
+ static_routes_input,
+ next_hop=DEFAULT_ROUTE_NXT_HOP_LINK1[addr_type],
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure network command on R1 (0.0.0.0/0 and 0::0/0) for IPv4 and IPv6 address family "
+ )
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {"network": [DEFAULT_ROUTES[addr_type]]}
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify 0.0.0.0/0 and 0::0/0 route also get advertised from link-2 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "Before removing default originate from R1 link -1 IPv4 and IPv6 address family taking the uptime snapshot"
+ )
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove default originate from R1 link -1 IPv4 and IPv6 address family ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Routes must be learned from network command")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("After removing the default originate on R1 taking the uptime snapshot")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After removing the default-originate uptime should get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before configuring default - originate")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "Configure default-originate on R1 link-1 again for IPv4 and IPv6 address family"
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify No change on R2 routing and BGP table for both the links ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking snapshot after configuring default - originate")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After configuring the default-originate uptime should not get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=True)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=True)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before removing network 0.0.0.0 ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove network command from R1 IPv4/IPv6 address family ")
+ DEFAULT_ROUTES = {"ipv4": "0.0.0.0/0", "ipv6": "0::0/0"}
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [DEFAULT_ROUTES[addr_type]],
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify 0.0.0.0/0 and 0::0/0 route get removed from link-2 and default-originate IPv4/IPv6 route learn on link-1"
+ )
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Route from link2 is not expected \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed\n Route from link2 is not expected \n Error: {}".format(
+ tc_name, result
+ )
+
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After removing default originate command on R1 verify that the uptime got reset on R2"
+ )
+
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before configuring static route network")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "Configure static default route for IPv4 and IPv6 (0.0.0.0/0 next-hop Null0 and 0::0/0 next-hop Null0) on R1"
+ )
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": "0.0.0.0/0",
+ "next_hop": NEXT_HOP_IP["ipv4"],
+ },
+ {
+ "network": "0::0/0",
+ "next_hop": NEXT_HOP_IP["ipv6"],
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("verifyIPv4 and IPv6 static routes are configure and up on R1 ")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": "0.0.0.0/0",
+ "next_hop": NEXT_HOP_IP["ipv4"],
+ },
+ {
+ "network": "0::0/0",
+ "next_hop": NEXT_HOP_IP["ipv6"],
+ },
+ ]
+ }
+ }
+ result = verify_fib_routes(tgen, addr_type, "r1", static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure redistribute static on IPv4 and IPv6 address family")
+ redistribute_static = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, redistribute_static)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("verify 0.0.0.0/0 and 0::0/0 route also get advertised from link-2 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert (
+ result is not True
+ ), "Testcase {} : Failed\n Best Path sould be advertised in routes\n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Taking uptime snapshot before removing default originate")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove default-originate from link-1 from IPv4 and IPv6 neighbor ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot after removing default originate")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("verify the up time , up time should get reset ")
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before configuring default originate")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ " Configure default-originate on link-1 again for IPv4 and IPv6 address family"
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot after configuring default originate")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("After configuring the default originate the uptime should not get reset ")
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before removing redisctribute static ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove redistribute static from IPv4 and IPv6 address family ")
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "local_as": get_dut_as_number(tgen, dut="r1"),
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [{"redist_type": "static", "delete": True}]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [{"redist_type": "static", "delete": True}]
+ }
+ },
+ },
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify No change on IPv4/IPv6 default-originate route advertised from link1")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Taking uptime snapshot before removing redisctribute static ")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("After removing default originate the route uptime should get reset ")
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=True)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=True)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_default_originate_with_aggregate_summary_p1(request):
+ """
+ Summary: "Verify default-originate route with aggregate summary command"
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ step("After changing the BGP AS Path Verify the BGP Convergence")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Configure default-originate on R1 IPv4 and IPv6 BGP session link-1 only")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {"r2": {"dest-link": "r1-link1"}}
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {"r2": {"dest-link": "r1-link1"}}
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify IPv4/IPv6 default originate routes present on R2 nexthop as link-1,on R2"
+ )
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Configure 5 static route for IPv4 and IPv6 on R0")
+ for addr_type in ADDR_TYPES:
+ input_advertise = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK1_3[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK1_4[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK1_5[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_advertise)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Before configuring the aggregate route taking uptime snapshot ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Configure aggregate summary command for IPv4 and IPv6 address family ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ raw_config = {
+ "r1": {
+ "raw_config": [
+ "router bgp {}".format(local_as),
+ "address-family ipv4 unicast",
+ "aggregate-address {} summary-only".format("0.0.0.0/0 "),
+ "exit-address-family",
+ "address-family ipv6 unicast",
+ "aggregate-address {} summary-only".format("0::0/0"),
+ "exit-address-family",
+ ]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "verify that no change on IPv4/IPv6 default-originate route advertised from link1 0.0.0.0/0 and 0::0/0 route also get advertised from link-2 on R2"
+ )
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("After configuring the aggregate route taking uptime snapshot ")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After Configuring the aggregate route uptime should get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Before removing default originate taking uptime snapshot ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("Remove default originate from R1 link -1 IPv4 and IPv6 address family")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {"dest-link": "r1-link1", "delete": True}
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "verify that no change on IPv4/IPv6 default-originate route advertised from link1 0.0.0.0/0 and 0::0/0 route also get advertised from link-2 on R2"
+ )
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("After removing default origin taking uptime snapshot ")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After removing the default-originate uptime should get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Before Configuring default origin taking uptime snapshot ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "Configure default-originate on R1 link-1 again for IPv4 and IPv6 address family"
+ )
+ local_as = get_dut_as_number(tgen, dut="r1")
+ default_originate_config = {
+ "r1": {
+ "bgp": {
+ "local_as": local_as,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "default_originate": {
+ "r2": {
+ "dest-link": "r1-link1",
+ }
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, default_originate_config)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("After Configuring default originate taking uptime snapshot")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step(
+ "After Configuring the default-originate uptime should get reset for link-1 learn route"
+ )
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Before removing aggregate -summary command taking the uptime snapshot ")
+ uptime_before_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_before_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("remove aggregate summary command for IPv4 and IPv6 address family ")
+ local_as = get_dut_as_number(tgen, dut="r1")
+ raw_config = {
+ "r1": {
+ "raw_config": [
+ "router bgp {}".format(local_as),
+ "address-family ipv4 unicast",
+ "no aggregate-address {} summary-only".format("0.0.0.0/0"),
+ "exit-address-family",
+ "address-family ipv6 unicast",
+ "no aggregate-address {} summary-only".format("0::0/0"),
+ "exit-address-family",
+ ]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify Default-originate IPv4/IPv6 route learn on link-1 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK1,
+ )
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify 0.0.0.0/0 and 0::0/0 route get removed from link-2 ")
+ result = verify_rib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ result = verify_fib_default_route(
+ tgen,
+ topo,
+ dut="r2",
+ routes=DEFAULT_ROUTES,
+ expected_nexthop=DEFAULT_ROUTE_NXT_HOP_LINK2,
+ expected=False,
+ )
+ assert result is not True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("After removing aggregate -summary command taking the uptime snapshot ")
+ uptime_after_ipv4 = get_rib_route_uptime(tgen, "ipv4", "r2", ipv4_uptime_dict)
+ uptime_after_ipv6 = get_rib_route_uptime(tgen, "ipv6", "r2", ipv6_uptime_dict)
+
+ step("After removing aggregate command uptime should get reset ")
+ result = verify_the_uptime(uptime_before_ipv4, uptime_after_ipv4, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ result = verify_the_uptime(uptime_before_ipv6, uptime_after_ipv6, incremented=False)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py
index ee71ae16e0..814272374a 100644
--- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py
+++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py
@@ -82,6 +82,8 @@ from lib.common_config import (
)
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py
index a9987a8f96..8e6f930633 100644
--- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py
+++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py
@@ -81,6 +81,8 @@ from lib.common_config import (
)
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py
index 95511568c6..9e5250406b 100644
--- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py
+++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_3.py
@@ -68,6 +68,7 @@ from lib.common_config import (
check_router_status,
)
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
@@ -1138,6 +1139,7 @@ def test_verify_default_originate_after_BGP_and_FRR_restart_p2(request):
write_test_footer(tc_name)
+
def test_verify_default_originate_after_shut_no_shut_bgp_neighbor_p1(request):
"""
Summary: "Verify default-originate route after shut/no shut and clear BGP neighbor "
@@ -2532,6 +2534,7 @@ def test_verify_default_originate_after_shut_no_shut_bgp_neighbor_p1(request):
write_test_footer(tc_name)
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py
index d330a04439..fa5164fb71 100644
--- a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py
+++ b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py
@@ -73,6 +73,8 @@ from lib.common_config import (
delete_route_maps,
)
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Save the Current Working Directory to find configuration files.
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
diff --git a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py
index 272a7fe291..9e3a3b5660 100644
--- a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py
+++ b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py
@@ -74,6 +74,8 @@ CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))
sys.path.append(os.path.join(CWD, "../lib/"))
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Required to instantiate the topology builder class.
# pylint: disable=C0413
diff --git a/tests/topotests/bgp_default_route_route_map_match/r1/zebra.conf b/tests/topotests/bgp_default_route_route_map_match/r1/zebra.conf
index 9e581a7be7..0a283c06d5 100644
--- a/tests/topotests/bgp_default_route_route_map_match/r1/zebra.conf
+++ b/tests/topotests/bgp_default_route_route_map_match/r1/zebra.conf
@@ -5,7 +5,5 @@ interface lo
interface r1-eth0
ip address 192.168.255.1/24
!
-ip route 192.168.13.0./24 Null0
-!
ip forwarding
!
diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_ibgp_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_ibgp_nbr.py
index 68436177d8..9f01287c91 100644
--- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_ibgp_nbr.py
+++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_ibgp_nbr.py
@@ -56,6 +56,9 @@ from lib.bgp import (
)
from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Global variables
topo = None
diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_nbr.py
index 1d424caa30..48f308e316 100644
--- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_nbr.py
+++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_nbr.py
@@ -55,6 +55,8 @@ from lib.bgp import (
)
from lib.topojson import build_config_from_json
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Global variables
topo = None
diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py
index fc2d2364c6..4105c3fe63 100644
--- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py
+++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py
@@ -52,6 +52,8 @@ from lib.bgp import create_router_bgp, verify_bgp_convergence, verify_bgp_rib
from lib.topojson import build_config_from_json
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Global variables
topo = None
diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_nbr.py
index 862cae42e9..a9e6d21b8d 100644
--- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_nbr.py
+++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_nbr.py
@@ -58,9 +58,10 @@ from lib.bgp import (
)
from lib.topojson import build_config_from_json
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
# Global variables
topo = None
-
# Global variables
NETWORK = {
"ipv4": [
diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_unnumbered_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_unnumbered_nbr.py
index 1a91257f06..9a0fc44175 100644
--- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_unnumbered_nbr.py
+++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ibgp_unnumbered_nbr.py
@@ -54,6 +54,7 @@ from lib.topojson import build_config_from_json
# Global variables
topo = None
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
# Global variables
NETWORK_CMD_IP = "1.0.1.17/32"
diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py
index d612ad2c94..bc53dfb469 100755
--- a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py
+++ b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py
@@ -38,6 +38,7 @@ sys.path.append(os.path.join(CWD, "../"))
# Import topogen and topotest helpers
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.snmptest import SnmpTester
+from lib import topotest
# Required to instantiate the topology builder class.
@@ -239,10 +240,18 @@ def test_pe1_converge_evpn():
tgen = get_topogen()
r1 = tgen.gears["r1"]
- r1_snmp = SnmpTester(r1, "10.1.1.1", "public", "2c")
+ def _convergence():
+ r1 = tgen.gears["r1"]
+ r1_snmp = SnmpTester(r1, "10.1.1.1", "public", "2c")
+
+ return r1_snmp.test_oid("bgpVersion", "10")
+
+ _, result = topotest.run_and_expect(_convergence, True, count=20, wait=1)
assertmsg = "BGP SNMP does not seem to be running"
- assert r1_snmp.test_oid("bgpVersion", "10"), assertmsg
+ assert result, assertmsg
+
+ r1_snmp = SnmpTester(r1, "10.1.1.1", "public", "2c")
count = 0
passed = False
while count < 125:
diff --git a/tests/topotests/bgp_vpnv4_noretain/__init__.py b/tests/topotests/bgp_vpnv4_noretain/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/__init__.py
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/bgpd.conf b/tests/topotests/bgp_vpnv4_noretain/r1/bgpd.conf
new file mode 100644
index 0000000000..3d8773b8bf
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/bgpd.conf
@@ -0,0 +1,24 @@
+router bgp 65500
+ bgp router-id 1.1.1.1
+ neighbor 10.125.0.2 remote-as 65500
+ address-family ipv4 unicast
+ no neighbor 10.125.0.2 activate
+ exit-address-family
+ address-family ipv4 vpn
+ neighbor 10.125.0.2 activate
+ no bgp retain route-target all
+ exit-address-family
+!
+router bgp 65500 vrf vrf1
+ bgp router-id 1.1.1.1
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export 101
+ rd vpn export 444:1
+ rt vpn import 51:100 52:100
+ rt vpn export 51:100
+ export vpn
+ import vpn
+ exit-address-family
+!
+
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes.json
new file mode 100644
index 0000000000..903c4603c5
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes.json
@@ -0,0 +1,69 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "tableVersion":1,
+ "routerId":"1.1.1.1",
+ "defaultLocPrf":100,
+ "localAS":65500,
+ "routes":{
+ "routeDistinguishers":{
+ "444:1":{
+ "10.201.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"10.201.0.0",
+ "prefixLen":24,
+ "network":"10.201.0.0\/24",
+ "version":1,
+ "metric":0,
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"incomplete",
+ "announceNexthopSelf":true,
+ "nhVrfName":"vrf1",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ },
+ "444:2":{
+ "10.200.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"internal",
+ "prefix":"10.200.0.0",
+ "prefixLen":24,
+ "network":"10.200.0.0\/24",
+ "version":1,
+ "metric":0,
+ "locPrf":100,
+ "weight":0,
+ "peerId":"10.125.0.2",
+ "path":"",
+ "origin":"incomplete",
+ "nexthops":[
+ {
+ "ip":"10.125.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ },
+ "444:3":{
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes_unfiltered.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes_unfiltered.json
new file mode 100644
index 0000000000..3cc0b4a5f5
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes_unfiltered.json
@@ -0,0 +1,94 @@
+{
+ "vrfId":0,
+ "vrfName":"default",
+ "tableVersion":1,
+ "routerId":"1.1.1.1",
+ "defaultLocPrf":100,
+ "localAS":65500,
+ "routes":{
+ "routeDistinguishers":{
+ "444:1":{
+ "10.201.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"external",
+ "prefix":"10.201.0.0",
+ "prefixLen":24,
+ "network":"10.201.0.0\/24",
+ "version":1,
+ "metric":0,
+ "weight":32768,
+ "peerId":"(unspec)",
+ "path":"",
+ "origin":"incomplete",
+ "announceNexthopSelf":true,
+ "nhVrfName":"vrf1",
+ "nexthops":[
+ {
+ "ip":"0.0.0.0",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ },
+ "444:2":{
+ "10.200.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"internal",
+ "prefix":"10.200.0.0",
+ "prefixLen":24,
+ "network":"10.200.0.0\/24",
+ "version":1,
+ "metric":0,
+ "locPrf":100,
+ "weight":0,
+ "peerId":"10.125.0.2",
+ "path":"",
+ "origin":"incomplete",
+ "nexthops":[
+ {
+ "ip":"10.125.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ },
+ "444:3":{
+ "10.210.0.0/24":[
+ {
+ "valid":true,
+ "bestpath":true,
+ "selectionReason":"First path received",
+ "pathFrom":"internal",
+ "prefix":"10.210.0.0",
+ "prefixLen":24,
+ "network":"10.210.0.0\/24",
+ "version":1,
+ "metric":0,
+ "locPrf":100,
+ "weight":0,
+ "peerId":"10.125.0.2",
+ "path":"",
+ "origin":"incomplete",
+ "nexthops":[
+ {
+ "ip":"10.125.0.2",
+ "afi":"ipv4",
+ "used":true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf b/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf
new file mode 100644
index 0000000000..6f5cb6ec68
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/isisd.conf
@@ -0,0 +1,14 @@
+interface r1-eth0
+ ip router isis 1
+ isis circuit-type level-1
+!
+interface lo
+ ip router isis 1
+ isis passive
+!
+router isis 1
+ is-type level-1
+ net 49.0002.0000.1994.00
+ segment-routing on
+ segment-routing prefix 1.1.1.1/32 index 11
+!
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/zebra.conf b/tests/topotests/bgp_vpnv4_noretain/r1/zebra.conf
new file mode 100644
index 0000000000..5b8b1e8ffb
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/zebra.conf
@@ -0,0 +1,13 @@
+log stdout
+interface lo
+ ip address 1.1.1.1/32
+!
+interface r1-gre0
+ ip address 192.168.0.1/24
+!
+interface r1-eth1 vrf vrf1
+ ip address 10.201.0.1/24
+!
+interface r1-eth0
+ ip address 10.125.0.1/24
+!
diff --git a/tests/topotests/bgp_vpnv4_noretain/r2/bgpd.conf b/tests/topotests/bgp_vpnv4_noretain/r2/bgpd.conf
new file mode 100644
index 0000000000..235fb31177
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r2/bgpd.conf
@@ -0,0 +1,35 @@
+router bgp 65500
+ bgp router-id 2.2.2.2
+ neighbor 10.125.0.1 remote-as 65500
+ address-family ipv4 unicast
+ no neighbor 10.125.0.1 activate
+ exit-address-family
+ address-family ipv4 vpn
+ neighbor 10.125.0.1 activate
+ no bgp retain route-target all
+ exit-address-family
+!
+router bgp 65500 vrf vrf1
+ bgp router-id 2.2.2.2
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export 102
+ rd vpn export 444:2
+ rt vpn import 53:100 52:100 51:100
+ rt vpn export 52:100
+ export vpn
+ import vpn
+ exit-address-family
+!
+router bgp 65500 vrf vrf2
+ bgp router-id 2.2.2.2
+ address-family ipv4 unicast
+ redistribute connected
+ label vpn export 102
+ rd vpn export 444:3
+ rt vpn both 53:100 52:100 51:100
+ rt vpn both 53:100
+ export vpn
+ import vpn
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf b/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf
new file mode 100644
index 0000000000..cbec8c3674
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r2/isisd.conf
@@ -0,0 +1,14 @@
+interface r2-eth0
+ ip router isis 1
+ isis circuit-type level-1
+!
+interface lo
+ ip router isis 1
+ isis passive
+!
+router isis 1
+ is-type level-1
+ net 49.0002.0000.1995.00
+ segment-routing on
+ segment-routing prefix 2.2.2.2/32 index 22
+!
diff --git a/tests/topotests/bgp_vpnv4_noretain/r2/zebra.conf b/tests/topotests/bgp_vpnv4_noretain/r2/zebra.conf
new file mode 100644
index 0000000000..7ec644ac2a
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r2/zebra.conf
@@ -0,0 +1,16 @@
+log stdout
+interface lo
+ ip address 2.2.2.2/32
+!
+interface r2-gre0
+ ip address 192.168.0.2/24
+!
+interface r2-eth1 vrf vrf1
+ ip address 10.200.0.2/24
+!
+interface r2-eth2 vrf vrf2
+ ip address 10.210.0.2/24
+!
+interface r2-eth0
+ ip address 10.125.0.2/24
+!
diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py
new file mode 100644
index 0000000000..b4a841d9cf
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py
@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_vpnv4_noretain.py
+# Part of NetDEF Topology Tests
+#
+# Copyright 2022 6WIND S.A.
+#
+# 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_bgp_vpnv4_noretain.py: Do not keep the VPNvx entries when no
+ VRF matches incoming VPNVx entries
+"""
+
+import os
+import sys
+import json
+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.
+
+
+pytestmark = [pytest.mark.bgpd]
+
+def build_topo(tgen):
+ "Build function"
+
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+
+ 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 = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r2"])
+
+
+def _populate_iface():
+ tgen = get_topogen()
+ cmds_list = [
+ 'modprobe mpls_router',
+ 'echo 100000 > /proc/sys/net/mpls/platform_labels',
+ 'ip link add vrf1 type vrf table 10',
+ 'ip link set dev vrf1 up',
+ 'ip link set dev {0}-eth1 master vrf1',
+ 'echo 1 > /proc/sys/net/mpls/conf/vrf1/input',
+ ]
+ cmds_list_extra = [
+ 'ip link add vrf2 type vrf table 20',
+ 'ip link set dev vrf2 up',
+ 'ip link set dev {0}-eth2 master vrf2',
+ 'echo 1 > /proc/sys/net/mpls/conf/vrf2/input',
+ ]
+
+ for cmd in cmds_list:
+ input = cmd.format('r1', '1', '2')
+ logger.info('input: ' + cmd)
+ output = tgen.net['r1'].cmd(cmd.format('r1', '1', '2'))
+ logger.info('output: ' + output)
+
+ for cmd in cmds_list:
+ input = cmd.format('r2', '2', '1')
+ logger.info('input: ' + cmd)
+ output = tgen.net['r2'].cmd(cmd.format('r2', '2', '1'))
+ logger.info('output: ' + output)
+
+ for cmd in cmds_list_extra:
+ input = cmd.format('r2', '2', '1')
+ logger.info('input: ' + cmd)
+ output = tgen.net['r2'].cmd(cmd.format('r2', '2', '1'))
+ logger.info('output: ' + output)
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ _populate_iface()
+
+ for rname, router in router_list.items():
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_ISIS, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ # Initialize all routers.
+ tgen.start_router()
+
+
+def teardown_module(_mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ tgen.stop_topology()
+
+
+def test_protocols_convergence():
+ """
+ Assert that all protocols have converged
+ statuses as they depend on it.
+ """
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Check IPv4 VPN routing tables on r1
+ logger.info("Checking IPv4 routes for convergence on r1")
+ router = tgen.gears['r1']
+ json_file = "{}/{}/ipv4_vpn_routes.json".format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info("skipping file {}".format(json_file))
+ assert 0, 'ipv4_vpn_routes.json file not found'
+ return
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp,
+ router,
+ "show bgp ipv4 vpn json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+ # Check BGP IPv4 routing tables after unsetting no retain flag
+ logger.info("Checking BGP IPv4 routes for convergence on r2")
+ router = tgen.gears['r1']
+ router.vtysh_cmd("configure\nrouter bgp 65500\naddress-family ipv4 vpn\nbgp retain route-target all\n")
+
+ # Check IPv4 VPN routing tables on r1
+ logger.info("Checking IPv4 routes for convergence on r1")
+ router = tgen.gears['r1']
+ json_file = "{}/{}/ipv4_vpn_routes_unfiltered.json".format(CWD, router.name)
+ if not os.path.isfile(json_file):
+ logger.info("skipping file {}".format(json_file))
+ assert 0, 'ipv4_vpn_routes_unfiltered.json file not found'
+ return
+
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp,
+ router,
+ "show bgp ipv4 vpn json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 4afa86f740..fa33b02ed1 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -449,6 +449,8 @@ def check_router_status(tgen):
daemons.append("zebra")
if "pimd" in result:
daemons.append("pimd")
+ if "pim6d" in result:
+ daemons.append("pim6d")
if "ospfd" in result:
daemons.append("ospfd")
if "ospf6d" in result:
@@ -1035,6 +1037,12 @@ def start_topology(tgen, daemon=None):
TopoRouter.RD_PIM, "{}/{}/pimd.conf".format(tgen.logdir, rname)
)
+ if daemon and "pim6d" in daemon:
+ # Loading empty pimd.conf file to router, to start the pim6d deamon
+ router.load_config(
+ TopoRouter.RD_PIM6, "{}/{}/pim6d.conf".format(tgen.logdir, rname)
+ )
+
# Starting routers
logger.info("Starting all routers once topology is created")
tgen.start_router()
@@ -1131,6 +1139,8 @@ def topo_daemons(tgen, topo=None):
for val in topo["routers"][rtr]["links"].values():
if "pim" in val and "pimd" not in daemon_list:
daemon_list.append("pimd")
+ if "pim6" in val and "pim6d" not in daemon_list:
+ daemon_list.append("pim6d")
if "ospf" in val and "ospfd" not in daemon_list:
daemon_list.append("ospfd")
if "ospf6" in val and "ospf6d" not in daemon_list:
@@ -3234,6 +3244,86 @@ def configure_interface_mac(tgen, input_dict):
return True
+def socat_send_igmp_join_traffic(
+ tgen,
+ server,
+ protocol_option,
+ igmp_groups,
+ send_from_intf,
+ send_from_intf_ip=None,
+ port=12345,
+ reuseaddr=True,
+ join=False,
+ traffic=False,
+):
+ """
+ API to send IGMP join using SOCAT tool
+
+ Parameters:
+ -----------
+ * `tgen` : Topogen object
+ * `server`: iperf server, from where IGMP join would be sent
+ * `protocol_option`: Protocol options, ex: UDP6-RECV
+ * `igmp_groups`: IGMP group for which join has to be sent
+ * `send_from_intf`: Interface from which join would be sent
+ * `send_from_intf_ip`: Interface IP, default is None
+ * `port`: Port to be used, default is 12345
+ * `reuseaddr`: True|False, bydefault True
+ * `join`: If join needs to be sent
+ * `traffic`: If traffic needs to be sent
+
+ returns:
+ --------
+ errormsg or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ rnode = tgen.routers()[server]
+ socat_cmd = "socat -u "
+
+ # UDP4/TCP4/UDP6/UDP6-RECV
+ if protocol_option:
+ socat_cmd += "{}".format(protocol_option)
+
+ if port:
+ socat_cmd += ":{},".format(port)
+
+ if reuseaddr:
+ socat_cmd += "{},".format("reuseaddr")
+
+ # Group address range to cover
+ if igmp_groups:
+ if not isinstance(igmp_groups, list):
+ igmp_groups = [igmp_groups]
+
+ for igmp_group in igmp_groups:
+ if join:
+ join_traffic_option = "ipv6-join-group"
+ elif traffic:
+ join_traffic_option = "ipv6-join-group-source"
+
+ if send_from_intf and not send_from_intf_ip:
+ socat_cmd += "{}='[{}]:{}'".format(
+ join_traffic_option, igmp_group, send_from_intf
+ )
+ else:
+ socat_cmd += "{}='[{}]:{}:[{}]'".format(
+ join_traffic_option, igmp_group, send_from_intf, send_from_intf_ip
+ )
+
+ socat_cmd += " STDOUT"
+
+ socat_cmd += " &>{}/socat.logs &".format(tgen.logdir)
+
+ # Run socat command to send IGMP join
+ logger.info("[DUT: {}]: Running command: [{}]".format(server, socat_cmd))
+ output = rnode.run("set +m; {} sleep 0.5".format(socat_cmd))
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
#############################################
# Verification APIs
#############################################
diff --git a/tests/topotests/lib/micronet.py b/tests/topotests/lib/micronet.py
index 02f66e9c26..dfa10ccb2f 100644
--- a/tests/topotests/lib/micronet.py
+++ b/tests/topotests/lib/micronet.py
@@ -599,6 +599,60 @@ class LinuxNamespace(Commander):
self.cmd_raises("mkdir -p " + inner)
self.cmd_raises("mount --rbind {} {} ".format(outer, inner))
+ def add_vlan(self, vlanname, linkiface, vlanid):
+ self.logger.debug("Adding VLAN interface: %s (%s)", vlanname, vlanid)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ self.cmd_raises(
+ [
+ ip_path,
+ "link",
+ "add",
+ "link",
+ linkiface,
+ "name",
+ vlanname,
+ "type",
+ "vlan",
+ "id",
+ vlanid,
+ ]
+ )
+ self.cmd_raises([ip_path, "link", "set", "dev", vlanname, "up"])
+
+ def add_loop(self, loopname):
+ self.logger.debug("Adding Linux iface: %s", loopname)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ self.cmd_raises([ip_path, "link", "add", loopname, "type", "dummy"])
+ self.cmd_raises([ip_path, "link", "set", "dev", loopname, "up"])
+
+ def add_l3vrf(self, vrfname, tableid):
+ self.logger.debug("Adding Linux VRF: %s", vrfname)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ self.cmd_raises(
+ [ip_path, "link", "add", vrfname, "type", "vrf", "table", tableid]
+ )
+ self.cmd_raises([ip_path, "link", "set", "dev", vrfname, "up"])
+
+ def del_iface(self, iface):
+ self.logger.debug("Removing Linux Iface: %s", iface)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ self.cmd_raises([ip_path, "link", "del", iface])
+
+ def attach_iface_to_l3vrf(self, ifacename, vrfname):
+ self.logger.debug("Attaching Iface %s to Linux VRF %s", ifacename, vrfname)
+ ip_path = self.get_exec_path("ip")
+ assert ip_path, "XXX missing ip command!"
+ if vrfname:
+ self.cmd_raises(
+ [ip_path, "link", "set", "dev", ifacename, "master", vrfname]
+ )
+ else:
+ self.cmd_raises([ip_path, "link", "set", "dev", ifacename, "nomaster"])
+
def add_netns(self, ns):
self.logger.debug("Adding network namespace %s", ns)
diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py
index cd070e08b9..03ab02460f 100644
--- a/tests/topotests/lib/pim.py
+++ b/tests/topotests/lib/pim.py
@@ -36,6 +36,7 @@ from lib.common_config import (
InvalidCLIError,
retry,
run_frr_cmd,
+ validate_ip_address,
)
from lib.micronet import get_exec_path
from lib.topolog import logger
@@ -47,7 +48,7 @@ CWD = os.path.dirname(os.path.realpath(__file__))
def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True):
"""
- API to configure pim on router
+ API to configure pim/pimv6 on router
Parameters
----------
@@ -70,6 +71,16 @@ def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True
"prefix-list": "pf_list_1"
"delete": True
}]
+ },
+ "pim6": {
+ "disable" : ["l1-i1-eth1"],
+ "rp": [{
+ "rp_addr" : "2001:db8:f::5:17".
+ "keep-alive-timer": "100"
+ "group_addr_range": ["FF00::/8"]
+ "prefix-list": "pf_list_1"
+ "delete": True
+ }]
}
}
}
@@ -97,12 +108,8 @@ def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True
# Now add RP config to all routers
for router in input_dict.keys():
- if "pim" not in input_dict[router]:
- continue
- if "rp" not in input_dict[router]["pim"]:
- continue
- _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict)
-
+ if "pim" in input_dict[router] or "pim6" in input_dict[router]:
+ _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict)
try:
result = create_common_configurations(
tgen, config_data_dict, "pim", build, load_config
@@ -133,81 +140,123 @@ def _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict):
"""
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ rp_data = []
+
+ # PIMv4
+ pim_data = None
+ if "pim" in input_dict[router]:
+ pim_data = input_dict[router]["pim"]
+ if "rp" in input_dict[router]["pim"]:
+ rp_data += pim_data["rp"]
- pim_data = input_dict[router]["pim"]
- rp_data = pim_data["rp"]
+ # PIMv6
+ pim6_data = None
+ if "pim6" in input_dict[router]:
+ pim6_data = input_dict[router]["pim6"]
+ if "rp" in input_dict[router]["pim6"]:
+ rp_data += pim6_data["rp"]
# Configure this RP on every router.
for dut in tgen.routers():
# At least one interface must be enabled for PIM on the router
pim_if_enabled = False
+ pim6_if_enabled = False
for destLink, data in topo[dut]["links"].items():
if "pim" in data:
pim_if_enabled = True
- if not pim_if_enabled:
+ if "pim6" in data:
+ pim6_if_enabled = True
+ if not pim_if_enabled and pim_data:
+ continue
+ if not pim6_if_enabled and pim6_data:
continue
config_data = []
- for rp_dict in deepcopy(rp_data):
- # ip address of RP
- if "rp_addr" not in rp_dict and build:
- logger.error(
- "Router %s: 'ip address of RP' not " "present in input_dict/JSON",
- router,
- )
-
- return False
- rp_addr = rp_dict.setdefault("rp_addr", None)
-
- # Keep alive Timer
- keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None)
-
- # Group Address range to cover
- if "group_addr_range" not in rp_dict and build:
- logger.error(
- "Router %s:'Group Address range to cover'"
- " not present in input_dict/JSON",
- router,
- )
-
- return False
- group_addr_range = rp_dict.setdefault("group_addr_range", None)
+ if rp_data:
+ for rp_dict in deepcopy(rp_data):
+ # ip address of RP
+ if "rp_addr" not in rp_dict and build:
+ logger.error(
+ "Router %s: 'ip address of RP' not "
+ "present in input_dict/JSON",
+ router,
+ )
- # Group prefix-list filter
- prefix_list = rp_dict.setdefault("prefix_list", None)
+ return False
+ rp_addr = rp_dict.setdefault("rp_addr", None)
+ if rp_addr:
+ addr_type = validate_ip_address(rp_addr)
+ # Keep alive Timer
+ keep_alive_timer = rp_dict.setdefault("keep_alive_timer", None)
+
+ # Group Address range to cover
+ if "group_addr_range" not in rp_dict and build:
+ logger.error(
+ "Router %s:'Group Address range to cover'"
+ " not present in input_dict/JSON",
+ router,
+ )
- # Delete rp config
- del_action = rp_dict.setdefault("delete", False)
+ return False
+ group_addr_range = rp_dict.setdefault("group_addr_range", None)
- if keep_alive_timer:
- cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer)
- if del_action:
- cmd = "no {}".format(cmd)
- config_data.append(cmd)
+ # Group prefix-list filter
+ prefix_list = rp_dict.setdefault("prefix_list", None)
- if rp_addr:
- if group_addr_range:
- if type(group_addr_range) is not list:
- group_addr_range = [group_addr_range]
+ # Delete rp config
+ del_action = rp_dict.setdefault("delete", False)
- for grp_addr in group_addr_range:
- cmd = "ip pim rp {} {}".format(rp_addr, grp_addr)
+ if keep_alive_timer:
+ if addr_type == "ipv4":
+ cmd = "ip pim rp keep-alive-timer {}".format(keep_alive_timer)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ if addr_type == "ipv6":
+ cmd = "ipv6 pim rp keep-alive-timer {}".format(keep_alive_timer)
if del_action:
cmd = "no {}".format(cmd)
config_data.append(cmd)
- if prefix_list:
- cmd = "ip pim rp {} prefix-list {}".format(rp_addr, prefix_list)
- if del_action:
- cmd = "no {}".format(cmd)
- config_data.append(cmd)
+ if rp_addr:
+ if group_addr_range:
+ if type(group_addr_range) is not list:
+ group_addr_range = [group_addr_range]
- if config_data:
- if dut not in config_data_dict:
- config_data_dict[dut] = config_data
- else:
- config_data_dict[dut].extend(config_data)
+ for grp_addr in group_addr_range:
+ if addr_type == "ipv4":
+ cmd = "ip pim rp {} {}".format(rp_addr, grp_addr)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ if addr_type == "ipv6":
+ cmd = "ipv6 pim rp {} {}".format(rp_addr, grp_addr)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if prefix_list:
+ if addr_type == "ipv4":
+ cmd = "ip pim rp {} prefix-list {}".format(
+ rp_addr, prefix_list
+ )
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+ if addr_type == "ipv6":
+ cmd = "ipv6 pim rp {} prefix-list {}".format(
+ rp_addr, prefix_list
+ )
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if config_data:
+ if dut not in config_data_dict:
+ config_data_dict[dut] = config_data
+ else:
+ config_data_dict[dut].extend(config_data)
def create_igmp_config(tgen, topo, input_dict=None, build=False):
@@ -319,6 +368,121 @@ def create_igmp_config(tgen, topo, input_dict=None, build=False):
return result
+def create_mld_config(tgen, topo, input_dict=None, build=False):
+ """
+ API to configure mld for PIMv6 on router
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `input_dict` : Input dict data, required when configuring from
+ testcase
+ * `build` : Only for initial setup phase this is set as True.
+
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "mld": {
+ "interfaces": {
+ "r1-r0-eth0" :{
+ "mld":{
+ "version": "2",
+ "delete": True
+ "query": {
+ "query-interval" : 100,
+ "query-max-response-time": 200
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Returns
+ -------
+ True or False
+ """
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ result = False
+ if not input_dict:
+ input_dict = deepcopy(topo)
+ else:
+ topo = topo["routers"]
+ input_dict = deepcopy(input_dict)
+ for router in input_dict.keys():
+ if "mld" not in input_dict[router]:
+ logger.debug("Router %s: 'mld' is not present in " "input_dict", router)
+ continue
+
+ mld_data = input_dict[router]["mld"]
+
+ if "interfaces" in mld_data:
+ config_data = []
+ intf_data = mld_data["interfaces"]
+
+ for intf_name in intf_data.keys():
+ cmd = "interface {}".format(intf_name)
+ config_data.append(cmd)
+ protocol = "mld"
+ del_action = intf_data[intf_name]["mld"].setdefault("delete", False)
+ cmd = "ipv6 mld"
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ del_attr = intf_data[intf_name]["mld"].setdefault("delete_attr", False)
+ join = intf_data[intf_name]["mld"].setdefault("join", None)
+ source = intf_data[intf_name]["mld"].setdefault("source", None)
+ version = intf_data[intf_name]["mld"].setdefault("version", False)
+ query = intf_data[intf_name]["mld"].setdefault("query", {})
+
+ if version:
+ cmd = "ipv6 {} version {}".format(protocol, version)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if source and join:
+ for group in join:
+ cmd = "ipv6 {} join {} {}".format(protocol, group, source)
+
+ if del_attr:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ elif join:
+ for group in join:
+ cmd = "ipv6 {} join {}".format(protocol, group)
+
+ if del_attr:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ if query:
+ for _query, value in query.items():
+ if _query != "delete":
+ cmd = "ipv6 {} {} {}".format(protocol, _query, value)
+
+ if "delete" in intf_data[intf_name][protocol]["query"]:
+ cmd = "no {}".format(cmd)
+
+ config_data.append(cmd)
+ try:
+ result = create_common_configuration(
+ tgen, router, config_data, "interface_config", build=build
+ )
+ except InvalidCLIError:
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return result
+
+
def _enable_disable_pim_config(tgen, topo, input_dict, router, build=False):
"""
Helper API to enable or disable pim on interfaces
@@ -338,7 +502,7 @@ def _enable_disable_pim_config(tgen, topo, input_dict, router, build=False):
config_data = []
- # Enable pim on interfaces
+ # Enable pim/pim6 on interfaces
for destRouterLink, data in sorted(topo[router]["links"].items()):
if "pim" in data and data["pim"] == "enable":
# Loopback interfaces
@@ -351,6 +515,17 @@ def _enable_disable_pim_config(tgen, topo, input_dict, router, build=False):
config_data.append(cmd)
config_data.append("ip pim")
+ if "pim6" in data and data["pim6"] == "enable":
+ # Loopback interfaces
+ if "type" in data and data["type"] == "loopback":
+ interface_name = destRouterLink
+ else:
+ interface_name = data["interface"]
+
+ cmd = "interface {}".format(interface_name)
+ config_data.append(cmd)
+ config_data.append("ipv6 pim")
+
# pim global config
if "pim" in input_dict[router]:
pim_data = input_dict[router]["pim"]
@@ -366,6 +541,21 @@ def _enable_disable_pim_config(tgen, topo, input_dict, router, build=False):
cmd = "no {}".format(cmd)
config_data.append(cmd)
+ # pim6 global config
+ if "pim6" in input_dict[router]:
+ pim6_data = input_dict[router]["pim6"]
+ del_action = pim6_data.setdefault("delete", False)
+ for t in [
+ "join-prune-interval",
+ "keep-alive-timer",
+ "register-suppress-time",
+ ]:
+ if t in pim6_data:
+ cmd = "ipv6 pim {} {}".format(t, pim6_data[t])
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
return config_data
@@ -732,9 +922,6 @@ def verify_upstream_iif(
"[DUT: %s]: Verifying upstream Inbound Interface" " for IGMP groups received:",
dut,
)
- show_ip_pim_upstream_json = run_frr_cmd(
- rnode, "show ip pim upstream json", isjson=True
- )
if type(group_addresses) is not list:
group_addresses = [group_addresses]
@@ -742,6 +929,17 @@ def verify_upstream_iif(
if type(iif) is not list:
iif = [iif]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
+ cmd = "show {} pim upstream json".format(ip_cmd)
+ show_ip_pim_upstream_json = run_frr_cmd(rnode, cmd, isjson=True)
+
for grp_addr in group_addresses:
# Verify group address
if grp_addr not in show_ip_pim_upstream_json:
@@ -883,13 +1081,19 @@ def verify_join_state_and_timer(
"[DUT: %s]: Verifying Join state and Join Timer" " for IGMP groups received:",
dut,
)
- show_ip_pim_upstream_json = run_frr_cmd(
- rnode, "show ip pim upstream json", isjson=True
- )
if type(group_addresses) is not list:
group_addresses = [group_addresses]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ cmd = "show ip pim upstream json"
+ elif addr_type == "ipv6":
+ cmd = "show ipv6 pim upstream json"
+ show_ip_pim_upstream_json = run_frr_cmd(rnode, cmd, isjson=True)
+
for grp_addr in group_addresses:
# Verify group address
if grp_addr not in show_ip_pim_upstream_json:
@@ -1010,12 +1214,31 @@ def verify_mroutes(
rnode = tgen.routers()[dut]
+ if not isinstance(group_addresses, list):
+ group_addresses = [group_addresses]
+
+ if not isinstance(iif, list) and iif != "none":
+ iif = [iif]
+
+ if not isinstance(oil, list) and oil != "none":
+ oil = [oil]
+
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
if return_uptime:
logger.info("Sleeping for %s sec..", mwait)
sleep(mwait)
logger.info("[DUT: %s]: Verifying ip mroutes", dut)
- show_ip_mroute_json = run_frr_cmd(rnode, "show ip mroute json", isjson=True)
+ show_ip_mroute_json = run_frr_cmd(
+ rnode, "show {} mroute json".format(ip_cmd), isjson=True
+ )
if return_uptime:
uptime_dict = {}
@@ -1024,15 +1247,6 @@ def verify_mroutes(
error_msg = "[DUT %s]: mroutes are not present or flushed out !!" % (dut)
return error_msg
- if not isinstance(group_addresses, list):
- group_addresses = [group_addresses]
-
- if not isinstance(iif, list) and iif != "none":
- iif = [iif]
-
- if not isinstance(oil, list) and oil != "none":
- oil = [oil]
-
for grp_addr in group_addresses:
if grp_addr not in show_ip_mroute_json:
errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
@@ -1214,15 +1428,20 @@ def verify_pim_rp_info(
rnode = tgen.routers()[dut]
- logger.info("[DUT: %s]: Verifying ip rp info", dut)
- show_ip_rp_info_json = run_frr_cmd(rnode, "show ip pim rp-info json", isjson=True)
-
if type(group_addresses) is not list:
group_addresses = [group_addresses]
if type(oif) is not list:
oif = [oif]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
for grp_addr in group_addresses:
if rp is None:
rp_details = find_rp_details(tgen, topo)
@@ -1232,9 +1451,14 @@ def verify_pim_rp_info(
else:
iamRP = False
else:
- show_ip_route_json = run_frr_cmd(
- rnode, "show ip route connected json", isjson=True
- )
+ if addr_type == "ipv4":
+ show_ip_route_json = run_frr_cmd(
+ rnode, "show ip route connected json", isjson=True
+ )
+ elif addr_type == "ipv6":
+ show_ip_route_json = run_frr_cmd(
+ rnode, "show ipv6 route connected json", isjson=True
+ )
for _rp in show_ip_route_json.keys():
if rp == _rp.split("/")[0]:
iamRP = True
@@ -1242,16 +1466,27 @@ def verify_pim_rp_info(
else:
iamRP = False
+ logger.info("[DUT: %s]: Verifying ip rp info", dut)
+ cmd = "show {} pim rp-info json".format(ip_cmd)
+ show_ip_rp_info_json = run_frr_cmd(rnode, cmd, isjson=True)
+
if rp not in show_ip_rp_info_json:
- errormsg = "[DUT %s]: Verifying rp-info" "for rp_address %s [FAILED]!! " % (
- dut,
- rp,
+ errormsg = (
+ "[DUT %s]: Verifying rp-info "
+ "for rp_address %s [FAILED]!! " % (dut, rp)
)
return errormsg
else:
group_addr_json = show_ip_rp_info_json[rp]
for rp_json in group_addr_json:
+ if "rpAddress" not in rp_json:
+ errormsg = "[DUT %s]: %s key not " "present in rp-info " % (
+ dut,
+ "rpAddress",
+ )
+ return errormsg
+
if oif is not None:
found = False
if rp_json["outboundInterface"] not in oif:
@@ -1380,14 +1615,26 @@ def verify_pim_state(
rnode = tgen.routers()[dut]
logger.info("[DUT: %s]: Verifying pim state", dut)
- show_pim_state_json = run_frr_cmd(rnode, "show ip pim state json", isjson=True)
-
- if installed_fl is None:
- installed_fl = 1
if type(group_addresses) is not list:
group_addresses = [group_addresses]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
+ logger.info("[DUT: %s]: Verifying pim state", dut)
+ show_pim_state_json = run_frr_cmd(
+ rnode, "show {} pim state json".format(ip_cmd), isjson=True
+ )
+
+ if installed_fl is None:
+ installed_fl = 1
+
for grp_addr in group_addresses:
if src_address is None:
src_address = "*"
@@ -3635,7 +3882,7 @@ def verify_local_igmp_groups(tgen, dut, interface, group_addresses):
return True
-def verify_pim_interface_traffic(tgen, input_dict, return_stats=True):
+def verify_pim_interface_traffic(tgen, input_dict, return_stats=True, addr_type="ipv4"):
"""
Verify ip pim interface traffice by running
"show ip pim interface traffic" cli
@@ -3645,6 +3892,8 @@ def verify_pim_interface_traffic(tgen, input_dict, return_stats=True):
* `tgen`: topogen object
* `input_dict(dict)`: defines DUT, what and from which interfaces
traffic needs to be verified
+ * [optional]`addr_type`: specify address-family, default is ipv4
+
Usage
-----
input_dict = {
@@ -3675,9 +3924,13 @@ def verify_pim_interface_traffic(tgen, input_dict, return_stats=True):
rnode = tgen.routers()[dut]
logger.info("[DUT: %s]: Verifying pim interface traffic", dut)
- show_pim_intf_traffic_json = run_frr_cmd(
- rnode, "show ip pim interface traffic json", isjson=True
- )
+
+ if addr_type == "ipv4":
+ cmd = "show ip pim interface traffic json"
+ elif addr_type == "ipv6":
+ cmd = "show ipv6 pim interface traffic json"
+
+ show_pim_intf_traffic_json = run_frr_cmd(rnode, cmd, isjson=True)
output_dict[dut] = {}
for intf, data in input_dict[dut].items():
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index c04506f47e..c51a187f28 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -725,6 +725,7 @@ class TopoRouter(TopoGear):
RD_PBRD = 16
RD_PATH = 17
RD_SNMP = 18
+ RD_PIM6 = 19
RD = {
RD_FRR: "frr",
RD_ZEBRA: "zebra",
@@ -735,6 +736,7 @@ class TopoRouter(TopoGear):
RD_ISIS: "isisd",
RD_BGP: "bgpd",
RD_PIM: "pimd",
+ RD_PIM6: "pim6d",
RD_LDP: "ldpd",
RD_EIGRP: "eigrpd",
RD_NHRP: "nhrpd",
@@ -820,7 +822,8 @@ class TopoRouter(TopoGear):
Possible daemon values are: TopoRouter.RD_ZEBRA, TopoRouter.RD_RIP,
TopoRouter.RD_RIPNG, TopoRouter.RD_OSPF, TopoRouter.RD_OSPF6,
TopoRouter.RD_ISIS, TopoRouter.RD_BGP, TopoRouter.RD_LDP,
- TopoRouter.RD_PIM, TopoRouter.RD_PBR, TopoRouter.RD_SNMP.
+ TopoRouter.RD_PIM, TopoRouter.RD_PIM6, TopoRouter.RD_PBR,
+ TopoRouter.RD_SNMP.
Possible `source` values are `None` for an empty config file, a path name which is
used directly, or a file name with no path components which is first looked for
@@ -1276,6 +1279,7 @@ def diagnose_env_linux(rundir):
"ripngd",
"isisd",
"pimd",
+ "pim6d",
"ldpd",
"pbrd",
]:
diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py
index 3ca3353ed3..b49b09e636 100644
--- a/tests/topotests/lib/topojson.py
+++ b/tests/topotests/lib/topojson.py
@@ -41,7 +41,11 @@ from lib.common_config import (
number_to_column,
)
from lib.ospf import create_router_ospf
-from lib.pim import create_igmp_config, create_pim_config
+from lib.pim import (
+ create_igmp_config,
+ create_pim_config,
+ create_mld_config,
+)
from lib.topolog import logger
@@ -332,6 +336,7 @@ def build_config_from_json(tgen, topo=None, save_bkup=True):
("route_maps", create_route_maps),
("pim", create_pim_config),
("igmp", create_igmp_config),
+ ("mld", create_mld_config),
("bgp", create_router_bgp),
("ospf", create_router_ospf),
]
@@ -352,7 +357,9 @@ def build_config_from_json(tgen, topo=None, save_bkup=True):
logger.info("build_config_from_json: failed to configure topology")
pytest.exit(1)
- logger.info("Built config now clearing ospf neighbors as that router-id might not be what is used")
+ logger.info(
+ "Built config now clearing ospf neighbors as that router-id might not be what is used"
+ )
for ospf in ["ospf", "ospf6"]:
for router in data:
if ospf not in data[router]:
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index 27b566a8f5..5a3f586f82 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -1330,6 +1330,7 @@ class Router(Node):
"isisd": 0,
"bgpd": 0,
"pimd": 0,
+ "pim6d": 0,
"ldpd": 0,
"eigrpd": 0,
"nhrpd": 0,
diff --git a/tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json b/tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json
new file mode 100644
index 0000000000..9edfae4a24
--- /dev/null
+++ b/tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json
@@ -0,0 +1,197 @@
+{
+ "address_types": ["ipv6"],
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r0": {
+ "links": {
+ "r1": {"ipv6": "auto"}
+ }
+ },
+ "r1": {
+ "links": {
+ "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r0": {"ipv6": "auto", "pim6": "enable"},
+ "r2": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r3": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r4": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }}
+ },
+ "ospf6": {
+ "router_id": "100.1.1.0",
+ "neighbors": {
+ "r2": {},
+ "r3": {},
+ "r4": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ },
+ "mld": {
+ "interfaces": {
+ "r1-r0-eth0" :{
+ "mld":{
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r1": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r3": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }}
+ },
+ "ospf6": {
+ "router_id": "100.1.1.1",
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r1": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r2": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r4": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r5": {"ipv6": "auto", "pim6": "enable"}
+ },
+ "ospf6": {
+ "router_id": "100.1.1.2",
+ "neighbors": {
+ "r1": {},
+ "r2": {},
+ "r4": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r1": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }},
+ "r3": {"ipv6": "auto", "pim6": "enable",
+ "ospf6": {
+ "area": "0.0.0.0",
+ "hello_interval": 1,
+ "dead_interval": 4
+ }}
+ },
+ "ospf6": {
+ "router_id": "100.1.1.3",
+ "neighbors": {
+ "r1": {},
+ "r3": {}
+ },
+ "redistribute": [
+ {
+ "redist_type": "static"
+ },
+ {
+ "redist_type": "connected"
+ }
+ ]
+ }
+ },
+ "r5": {
+ "links": {
+ "r3": {"ipv6": "auto"}
+ }
+ }
+ }
+}
diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py
new file mode 100755
index 0000000000..bd5473a511
--- /dev/null
+++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py
@@ -0,0 +1,414 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Following tests are covered to test Multicast basic functionality:
+
+Topology:
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+TC_1 : Verify upstream interfaces(IIF) and join state are updated properly
+ after adding and deleting the static RP
+TC_2 : Verify IIF and OIL in "show ip pim state" updated properly after
+ adding and deleting the static RP
+TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
+TC_4: Verify (*,G) prune is send towards the RP after deleting the static RP
+TC_24 : Verify (*,G) and (S,G) populated correctly when SPT and RPT share the
+ same path
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+from time import sleep
+import datetime
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ step,
+ shutdown_bringup_interface,
+ kill_router_daemons,
+ start_router_daemons,
+ create_static_routes,
+ check_router_status,
+ socat_send_igmp_join_traffic,
+ topo_daemons
+)
+from lib.pim import (
+ create_pim_config,
+ verify_igmp_groups,
+ verify_upstream_iif,
+ verify_join_state_and_timer,
+ verify_mroutes,
+ verify_pim_neighbors,
+ verify_pim_interface_traffic,
+ verify_pim_rp_info,
+ verify_pim_state,
+ clear_pim_interface_traffic,
+ clear_igmp_interfaces,
+ clear_pim_interfaces,
+ clear_mroute,
+ clear_mroute_verify,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Global variables
+GROUP_RANGE_V6 = "ff08::/64"
+IGMP_JOIN_V6 = "ff08::1"
+STAR = "*"
+SOURCE = "Static"
+
+pytestmark = [pytest.mark.pimd]
+
+
+def build_topo(tgen):
+ """Build function"""
+
+ # Building topology from json file
+ build_topo_from_json(tgen, TOPO)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: %s", testsuite_run_time)
+ logger.info("=" * 40)
+
+ topology = """
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+ """
+ logger.info("Master Topology: \n %s", topology)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/multicast_pimv6_static_rp.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global TOPO
+ TOPO = tgen.json_topo
+
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, TOPO)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, TOPO)
+
+ # Verify PIM neighbors
+ result = verify_pim_neighbors(tgen, TOPO)
+ assert result is True, "setup_module :Failed \n Error:" " {}".format(result)
+
+ logger.info("Running setup_module() done")
+
+
+def teardown_module():
+ """Teardown the pytest environment"""
+
+ logger.info("Running teardown_module to delete topology")
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info("Testsuite end time: %s", time.asctime(time.localtime(time.time())))
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def verify_state_incremented(state_before, state_after):
+ """
+ API to compare interface traffic state incrementing
+
+ Parameters
+ ----------
+ * `state_before` : State dictionary for any particular instance
+ * `state_after` : State dictionary for any particular instance
+ """
+
+ for router, state_data in state_before.items():
+ for state, value in state_data.items():
+ if state_before[router][state] >= state_after[router][state]:
+ errormsg = (
+ "[DUT: %s]: state %s value has not"
+ " incremented, Initial value: %s, "
+ "Current value: %s [FAILED!!]"
+ % (
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: State %s value is "
+ "incremented, Initial value: %s, Current value: %s"
+ " [PASSED!!]",
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+
+ return True
+
+
+#####################################################
+
+def test_pimv6_add_delete_static_RP_p0(request):
+ """
+ TC_1: Verify upstream interfaces(IIF) and join state are updated
+ properly after adding and deleting the static RP
+ TC_2: Verify IIF and OIL in "show ip pim state" updated properly
+ after adding and deleting the static RP
+ TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
+ TC_4: Verify (*,G) prune is send towards the RP after deleting the
+ static RP
+
+ TOPOlogy used:
+ r0------r1-----r2
+ iperf DUT RP
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Shut link b/w R1 and R3 and R1 and R4 as per tescase topology")
+ intf_r1_r3 = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ intf_r1_r4 = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ for intf in [intf_r1_r3, intf_r1_r4]:
+ shutdown_bringup_interface(tgen, "r1", intf, ifaceaction=False)
+
+ step("Enable PIM between r1 and r2")
+ step("Enable MLD on r1 interface and send IGMP " "join (FF08::1) to r1")
+ step("Configure r2 loopback interface as RP")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_V6,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Verify show ip pim interface traffic without any mld join")
+ state_dict = {
+ "r1": {TOPO["routers"]["r1"]["links"]["r2"]["interface"]: ["pruneTx"]}
+ }
+
+ state_before = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
+ assert isinstance(
+ state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ step("send mld join (FF08::1) to R1")
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_igmp_join_traffic(
+ tgen, "r0", "UDP6-RECV", IGMP_JOIN_V6, intf, intf_ip, join=True
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ oif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ iif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_V6, oif, rp_address, SOURCE
+ )
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, oif, STAR, IGMP_JOIN_V6)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, oif, STAR, IGMP_JOIN_V6)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify PIM state")
+ result = verify_pim_state(tgen, dut, oif, iif, IGMP_JOIN_V6)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Verify ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, IGMP_JOIN_V6, oif, iif)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
+
+ step("r1: Delete RP configuration")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_V6,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_V6, oif, rp_address, SOURCE, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} :Failed \n " "RP: {} info is still present \n Error: {}".format(
+ tc_name, rp_address, result
+ )
+
+ step("r1: Verify upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, oif, STAR, IGMP_JOIN_V6, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Upstream ({}, {}) is still in join state \n Error: {}".format(
+ tc_name, STAR, IGMP_JOIN_V6, result
+ )
+ )
+
+ step("r1: Verify upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, oif, STAR, IGMP_JOIN_V6, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Upstream ({}, {}) timer is still running \n Error: {}".format(
+ tc_name, STAR, IGMP_JOIN_V6, result
+ )
+ )
+
+ step("r1: Verify PIM state")
+ result = verify_pim_state(tgen, dut, oif, iif, IGMP_JOIN_V6, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "PIM state for group: {} is still Active \n Error: {}".format(
+ tc_name, IGMP_JOIN_V6, result
+ )
+ )
+
+ step("r1: Verify ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, IGMP_JOIN_V6, oif, iif, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "mroute ({}, {}) is still present \n Error: {}".format(
+ tc_name, STAR, IGMP_JOIN_V6, result
+ )
+ )
+
+ step("r1: Verify show ip pim interface traffic without any IGMP join")
+ state_after = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
+ assert isinstance(
+ state_after, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_state_incremented(state_before, state_after)
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py
index 8c855620be..58d37a368c 100644
--- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py
+++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py
@@ -57,6 +57,8 @@ from lib.ospf import (
create_router_ospf,
)
+pytestmark = [pytest.mark.ospfd]
+
# Global variables
topo = None
Iters = 5
diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py
index e7d0621df8..85646a8fab 100644
--- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py
+++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper2.py
@@ -57,6 +57,8 @@ from lib.ospf import (
create_router_ospf,
)
+pytestmark = [pytest.mark.ospfd]
+
# Global variables
topo = None
Iters = 5
diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py
index 4cb3747c56..ec97c254d1 100644
--- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py
+++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py
@@ -57,6 +57,8 @@ from lib.ospf import (
create_router_ospf,
)
+pytestmark = [pytest.mark.ospfd]
+
# Global variables
topo = None
Iters = 5
diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py
index 3967f5f42a..59ba8236c7 100644
--- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py
+++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py
@@ -68,6 +68,7 @@ from lib.ospf import (
verify_ospf_summary,
)
+pytestmark = [pytest.mark.ospfd, pytest.mark.staticd]
# Global variables
topo = None