summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDonald Sharp <sharpd@cumulusnetworks.com>2020-05-21 07:40:17 -0400
committerGitHub <noreply@github.com>2020-05-21 07:40:17 -0400
commitbda6d3729f3af3aa3e45ae62f26a01b7fd13ea19 (patch)
treea2f04ba5ff58f01ea9a51e7f01c05272e624d125
parent080bfc6530b4a21678bad19015cae2ab41aa3d86 (diff)
parent1f88794b84d12abc7b4d5de13718c3f57c3360a1 (diff)
Merge pull request #6398 from kuldeepkash/bgp_multi_vrf
tests: Add bgp-multi-vrf test suites
-rwxr-xr-xtests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py2
-rwxr-xr-xtests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py2
-rw-r--r--tests/topotests/bgp_multi_vrf_topo1/bgp_multi_vrf_topo1.json884
-rwxr-xr-xtests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py6300
-rw-r--r--tests/topotests/bgp_multi_vrf_topo2/bgp_multi_vrf_topo2.json1277
-rwxr-xr-xtests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py2012
-rw-r--r--tests/topotests/lib/bgp.py662
-rw-r--r--tests/topotests/lib/common_config.py844
-rw-r--r--tests/topotests/lib/topojson.py3
9 files changed, 11656 insertions, 330 deletions
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
index fd3e7fd7d3..087ba21e5e 100755
--- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
@@ -295,7 +295,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
addr_type,
dut,
input_dict_1,
- next_hop=NEXT_HOPS[addr_type],
+ next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
protocol=protocol,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
index 94ffc71ef6..94409ff3e1 100755
--- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
@@ -296,7 +296,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
addr_type,
dut,
input_dict_1,
- next_hop=NEXT_HOPS[addr_type],
+ next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
protocol=protocol,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
diff --git a/tests/topotests/bgp_multi_vrf_topo1/bgp_multi_vrf_topo1.json b/tests/topotests/bgp_multi_vrf_topo1/bgp_multi_vrf_topo1.json
new file mode 100644
index 0000000000..327744d3a1
--- /dev/null
+++ b/tests/topotests/bgp_multi_vrf_topo1/bgp_multi_vrf_topo1.json
@@ -0,0 +1,884 @@
+{
+ "address_types": ["ipv4","ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "red1": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "blue1": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE_A",
+ "id": "1"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r1": {
+ "links": {
+ "red1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "red1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "blue1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "blue1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link1":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link1":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link2":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link2":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link3":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link3":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link4":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link4":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r2": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r1-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "red2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "red2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "blue2-link1": {"ipv4": "auto", "ipv6": "autor3", "vrf": "BLUE_A"},
+ "blue2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "red2": {
+ "links": {
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "blue2": {
+ "links": {
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE_A",
+ "id": "1"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
new file mode 100755
index 0000000000..aabce04f24
--- /dev/null
+++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
@@ -0,0 +1,6300 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Following tests are covered to test BGP Multi-VRF:
+
+FUNC_1:
+ Within each VRF, each address must be unambiguous on DUT.
+FUNC_2:
+ Different VRFs can have ambiguous/overlapping
+ addresses on DUT.
+FUNC_3:
+ Create static routes(IPv4+IPv6) associated to specific VRFs
+ and verify on DUT that same prefixes are present in corresponding
+ routing table.
+FUNC_4_&_5:
+ Each VRF should be mapped with a unique VLAN on DUT
+ for traffic segregation, when using a single physical interface.
+FUNC_6:
+ Advertise same set of prefixes from different VRFs
+ and verify on remote router that these prefixes are not
+ leaking to each other
+FUNC_7:
+ Redistribute Static routes and verify on remote routers
+ that routes are advertised within specific VRF instance, which
+ those static routes belong to.
+FUNC_8:
+ Test end to end traffic isolation based on VRF tables.
+FUNC_9:
+ Use static routes for inter-vrf communication
+ (route-leaking) on DUT.
+FUNC_10:
+ Verify intra-vrf and inter-vrf communication between
+ iBGP peers.
+FUNC_11:
+ Verify intra-vrf and inter-vrf communication
+ between eBGP peers.
+FUNC_12_a:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_b:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_c:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_d:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_e:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_f:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_13:
+ Configure a route-map on DUT to match traffic based
+ on a VRF interfaces.
+FUNC_14:
+ Test VRF-lite with Static+BGP originated routes.
+FUNC_15:
+ Configure prefix-lists on DUT and apply to BGP peers to
+ permit/deny prefixes.
+FUNC_16_1:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+FUNC_16_2:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+FUNC_16_3:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from mininet.topo import Topo
+
+from lib.common_config import (
+ step,
+ verify_rib,
+ start_topology,
+ write_test_header,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_route_maps,
+ create_static_routes,
+ create_prefix_lists,
+ create_interface_in_kernel,
+ kill_mininet_routers_process,
+ create_bgp_community_lists,
+ check_router_status,
+ apply_raw_config,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ clear_bgp,
+ verify_bgp_rib,
+ create_router_bgp,
+ verify_bgp_community,
+ verify_bgp_convergence,
+ verify_best_path_as_per_bgp_attribute,
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/bgp_multi_vrf_topo1.json".format(CWD)
+
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+NETWORK1_1 = {"ipv4": "1.1.1.1/32", "ipv6": "1::1/128"}
+NETWORK1_2 = {"ipv4": "1.1.1.2/32", "ipv6": "1::2/128"}
+NETWORK2_1 = {"ipv4": "2.1.1.1/32", "ipv6": "2::1/128"}
+NETWORK2_2 = {"ipv4": "2.1.1.2/32", "ipv6": "2::2/128"}
+NETWORK3_1 = {"ipv4": "3.1.1.1/32", "ipv6": "3::1/128"}
+NETWORK3_2 = {"ipv4": "3.1.1.2/32", "ipv6": "3::2/128"}
+NETWORK4_1 = {"ipv4": "4.1.1.1/32", "ipv6": "4::1/128"}
+NETWORK4_2 = {"ipv4": "4.1.1.2/32", "ipv6": "4::2/128"}
+NETWORK5_1 = {"ipv4": "5.1.1.1/32", "ipv6": "5::1/128"}
+NETWORK5_2 = {"ipv4": "5.1.1.2/32", "ipv6": "5::2/128"}
+NETWORK6_1 = {"ipv4": "6.1.1.1/32", "ipv6": "6::1/128"}
+NETWORK6_2 = {"ipv4": "6.1.1.2/32", "ipv6": "6::2/128"}
+NETWORK7_1 = {"ipv4": "7.1.1.1/32", "ipv6": "7::1/128"}
+NETWORK7_2 = {"ipv4": "7.1.1.2/32", "ipv6": "7::2/128"}
+NETWORK8_1 = {"ipv4": "8.1.1.1/32", "ipv6": "8::1/128"}
+NETWORK8_2 = {"ipv4": "8.1.1.2/32", "ipv6": "8::2/128"}
+
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+LOOPBACK_1 = {
+ "ipv4": "10.10.10.10/32",
+ "ipv6": "10::10:10/128",
+ "ipv4_mask": "255.255.255.255",
+ "ipv6_mask": None,
+}
+LOOPBACK_2 = {
+ "ipv4": "20.20.20.20/32",
+ "ipv6": "20::20:20/128",
+ "ipv4_mask": "255.255.255.255",
+ "ipv6_mask": None,
+}
+
+
+class CreateTopo(Topo):
+ """
+ Test BasicTopo - topology 1
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function"""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Kill stale mininet routers and process
+ kill_mininet_routers_process(tgen)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ 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
+ )
+
+ 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)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_address_unambiguous_within_each_vrf_p0(request):
+ """
+ FUNC_1:
+ Within each VRF, each address must be unambiguous on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Configure a set of static routes(IPv4+IPv6) in " "RED_A on router RED-1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure the same static routes(IPv4+IPv6) with a TAG value"
+ "of 500 in RED_A on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 500,
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ },
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes(IPv4+IPv6) is overridden and doesn't"
+ " have duplicate entries within VRF RED_A on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 500,
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, tag=500)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Make sure routes are not present in global routing table")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected Behaviour: Routes are not "
+ "present on Global Routing table \n Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_ambiguous_overlapping_addresses_in_different_vrfs_p0(request):
+ """
+ FUNC_2:
+ Different VRFs can have ambiguous/overlapping
+ addresses on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Configure a set of static routes(IPv4+IPv6) in vrf RED_A" "on router RED-1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure the same static routes(IPv4+IPv6) with a"
+ " TAG value of 500 in vrf RED_B on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 500,
+ "vrf": "RED_B",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that RED_A has the static routes without any" " TAG value")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, tag=500, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ step(
+ "Verify that RED_B has the same routes with TAG value "
+ "500 on same device RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 500,
+ "vrf": "RED_B",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, tag=500)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Make sure routes are not present in global routing table")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected Behaviour: Routes are not "
+ "present on Global Routing table \n Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_static_routes_associated_to_specific_vrfs_p0(request):
+ """
+ FUNC_3:
+ Create static routes(IPv4+IPv6) associated to specific VRFs
+ and verify on DUT that same prefixes are present in corresponding
+ routing table.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure a set of unique static(IPv4+IPv6) routes in vrf"
+ " RED_A on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure set of unique static routes(IPv4+IPv6) in vrf "
+ "RED_B on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes 1.x.x.x/32 and 1::x/128 appear" "in VRF RED_A table"
+ )
+ step(
+ "Verify that static routes 2.x.x.x/32 and 2::x/128 appear" "in VRF RED_B table"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that static routes 1.x.x.x/32 and 1::x/128 appear" "in VRF BLUE_A table"
+ )
+ step(
+ "Verify that static routes 2.x.x.x/32 and 2::x/128 appear" "in VRF BLUE_B table"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "blue1"
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Make sure routes are not present in global routing table")
+
+ for addr_type in ADDR_TYPES:
+ dut = "blue1"
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected Behaviour: Routes are not "
+ "present on Global Routing table \n Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_vrf_with_unique_physical_interface_p0(request):
+ """
+ FUNC_4_&_5:
+ Each VRF should be mapped with a unique VLAN on DUT
+ for traffic segregation, when using a single physical interface.
+
+ Each VRF should be mapped to a unique physical
+ interface(without VLAN tagging) on DUT for traffic segregation.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "R1 is receiving routes in 4 VRFs instances "
+ "(RED_A, RED_B, BLUE_A, BLUE_B) from RED_1 and BLUE_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise a set of unique BGP prefixes(IPv4+IPv6) from "
+ "routers RED_1 & BLUE_1 in each VRF using static redistribution"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Each VRF table on R2 should maintain it's associated "
+ "routes and and accordingly install in zebra"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_prefixes_leaking_p0(request):
+ """
+ FUNC_6:
+ Advertise same set of prefixes from different VRFs
+ and verify on remote router that these prefixes are not
+ leaking to each other
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Configure a set of static routes(IPv4+IPv6) in vrf " "RED_A on router RED-1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ },
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ }
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure a set of static routes(IPv4+IPv6) in vrf " "BLUE_A on router BLUE-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ }
+ ]
+ },
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ }
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure the same set of static routes with a "
+ "metric value of 123 in vrf RED_B on router RED-1"
+ )
+ step(
+ "Configure the same set of static routes with a "
+ "metric value of 123 in vrf BLUE_B on router BLUE-1"
+ )
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ },
+ },
+ ]
+ },
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify on R1 that RED_A doesn't receive and static "
+ "route with metric value 123"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ },
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ }
+ ]
+ },
+ }
+
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ }
+ ]
+ },
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ }
+ ]
+ },
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_1, metric=123, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, metric=123)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_2, metric=0, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+def test_static_routes_advertised_within_specific_vrf_p0(request):
+ """
+ FUNC_7:
+ Redistribute Static routes and verify on remote routers
+ that routes are advertised within specific VRF instance, which
+ those static routes belong to.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of unique BGP prefixes(IPv4+IPv6) "
+ "through static redistribution into VRF RED_A and RED_B"
+ " from router RED-1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same as above set of BGP prefixes(IPv4+IPv6) "
+ "through static redistribution into VRF BLUE_A and BLUE_B"
+ " from router BLUE-1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes are installed into vrfs RED_A"
+ "and RED_B tables only, not in global routing table of RED_1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that static routes are installed into vrfs BLUE_A and"
+ "BLUE_B tables only, not in global routing table of BLUE_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "blue1"
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify on router R1, that each set of prefixes is received"
+ " into associated vrf tables only."
+ )
+
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_end_to_end_traffic_isolation_p0(request):
+ """
+ FUNC_8:
+ Test end to end traffic isolation based on VRF tables.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1 "
+ "in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from BLUE_1 in"
+ " vrf instances(BLUE_A and BLUE_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Use below commands to send prefixes with as-path prepend"
+ "VRF BLUE_A and BLUE_B from router BLUE-1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "blue1": {
+ "route_maps": {
+ "ASP_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {"path": {"as_num": 123, "as_action": "prepend"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply route-map to neighbours")
+
+ input_dict_5 = {
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify on R1 that BLUE_A and BLUE_B VRFs are receiving the"
+ " prefixes with as-path 123 prepended."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_6 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_7 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Use below commands to send prefixes with as-path prepend VRF"
+ " BLUE_A and BLUE_B from router BLUE-1."
+ )
+
+ input_dict_6 = {
+ "red2": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ "blue2": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that router RED-2 receives the prefixes in respective" " VRF tables.")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red2"
+ input_dict_6 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "blue2"
+ input_dict_7 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_static_routes_for_inter_vrf_route_leaking_p0(request):
+ """
+ FUNC_9:
+ Use static routes for inter-vrf communication
+ (route-leaking) on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure unique loopback interfaces in VRFs RED_A "
+ "and RED_B on router RED_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ create_interface_in_kernel(
+ tgen,
+ "red1",
+ "loopback1",
+ LOOPBACK_1[addr_type],
+ "RED_A",
+ LOOPBACK_1["{}_mask".format(addr_type)],
+ )
+ create_interface_in_kernel(
+ tgen,
+ "red1",
+ "loopback2",
+ LOOPBACK_2[addr_type],
+ "RED_B",
+ LOOPBACK_2["{}_mask".format(addr_type)],
+ )
+
+ step(
+ "Create a static routes in vrf RED_B on router RED_1 pointing"
+ " next-hop as interface's IP in vrf RED_A"
+ )
+
+ intf_red1_r11 = topo["routers"]["red1"]["links"]["r1-link1"]["interface"]
+ intf_red1_r10 = topo["routers"]["red1"]["links"]["r1-link2"]["interface"]
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_red1_r10,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_A",
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes are installed into vrfs RED_A"
+ "and RED_B tables only, not in global routing table of RED_1"
+ )
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_red1_r10,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_A",
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_inter_vrf_and_intra_vrf_communication_iBGP_p0(request):
+ """
+ FUNC_10:
+ Verify intra-vrf and inter-vrf communication between
+ iBGP peers.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure unique loopback IP(IPv4+IPv6) in vrf RED_A on router"
+ " R1 and advertise it in BGP process using redistribute "
+ "connected command."
+ )
+
+ for addr_type in ADDR_TYPES:
+ create_interface_in_kernel(
+ tgen,
+ "r1",
+ "loopback1",
+ LOOPBACK_1[addr_type],
+ "RED_A",
+ LOOPBACK_1["{}_mask".format(addr_type)],
+ )
+
+ create_interface_in_kernel(
+ tgen,
+ "r1",
+ "loopback2",
+ LOOPBACK_2[addr_type],
+ "BLUE_A",
+ LOOPBACK_2["{}_mask".format(addr_type)],
+ )
+
+ step(
+ "Create a static routes in vrf RED_B on router RED_1 pointing"
+ " next-hop as interface's IP in vrf RED_A"
+ )
+
+ intf_r2_r12 = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+ intf_r2_r10 = topo["routers"]["r2"]["links"]["r1-link3"]["interface"]
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_r2_r10,
+ "nexthop_vrf": "BLUE_A",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_r2_r12,
+ "nexthop_vrf": "RED_A",
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute connected..")
+
+ input_dict_3 = {}
+ for dut in ["r1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "BLUE_A"]
+ AS_NUM = [100, 100]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["r2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "BLUE_A"]
+ AS_NUM = [100, 100]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes are installed into vrfs RED_A"
+ "and RED_B tables only, not in global routing table of RED_1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_r2_r10,
+ "nexthop_vrf": "BLUE_A",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_r2_r12,
+ "nexthop_vrf": "RED_A",
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_inter_vrf_and_intra_vrf_communication_eBGP_p0(request):
+ """
+ FUNC_11:
+ Verify intra-vrf and inter-vrf communication
+ between eBGP peers.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure unique loopback IP(IPv4+IPv6) in vrf RED_A on router"
+ " R2 and advertise it in BGP process using redistribute "
+ "connected command."
+ )
+
+ step(
+ "Configure unique loopback IP(IPv4+IPv6) in vrf BLUE_A on router"
+ " R2 and advertise it in BGP process using redistribute "
+ "connected command."
+ )
+
+ for addr_type in ADDR_TYPES:
+ create_interface_in_kernel(
+ tgen,
+ "r2",
+ "loopback1",
+ LOOPBACK_1[addr_type],
+ "RED_A",
+ LOOPBACK_1["{}_mask".format(addr_type)],
+ )
+ create_interface_in_kernel(
+ tgen,
+ "r2",
+ "loopback2",
+ LOOPBACK_2[addr_type],
+ "BLUE_A",
+ LOOPBACK_2["{}_mask".format(addr_type)],
+ )
+
+ step(
+ "Create a static routes in vrf RED_B on router RED_1 pointing"
+ " next-hop as interface's IP in vrf RED_A"
+ )
+
+ intf_r3_r21 = topo["routers"]["r3"]["links"]["r2-link1"]["interface"]
+ intf_r3_r23 = topo["routers"]["r3"]["links"]["r2-link3"]["interface"]
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_r3_r23,
+ "nexthop_vrf": "BLUE_A",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_r3_r21,
+ "nexthop_vrf": "RED_A",
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["r3"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "BLUE_A"]
+ AS_NUM = [200, 200]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Redistribute connected..")
+
+ input_dict_3 = {}
+ for dut in ["r2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "BLUE_A"]
+ AS_NUM = [100, 100]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes are installed into vrfs RED_A"
+ "and RED_B tables only, not in global routing table of RED_1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_r3_r23,
+ "nexthop_vrf": "BLUE_A",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_r3_r21,
+ "nexthop_vrf": "RED_A",
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_within_vrf_to_alter_bgp_attribute_nexthop_p0(request):
+ """
+ FUNC_12_a:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of BGP prefixes(IPv4+IPv6) from RED_1 and"
+ " RED_2 in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Delete nexthop-self configure from r1")
+
+ input_dict_4 = {
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link2": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link2": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link3": {"next_hop_self": False}
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link3": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link4": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link4": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because"
+ " nexthop-self config is deleted \n Error {}".format(tc_name, result)
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because"
+ " nexthop-self config is deleted \n Error {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+@pytest.mark.parametrize("attribute", ["locPrf", "weight", "metric"])
+def test_route_map_within_vrf_to_alter_bgp_attribute_p0(request, attribute):
+ """
+ FUNC_12_b/c/d:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of BGP prefixes(IPv4+IPv6) from RED_1 and"
+ " RED_2 in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ "red2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ "blue2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "red2", "blue1", "blue2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to influence BGP parameters - " " Local Preference")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "route_maps": {
+ "rmap_r1_{}".format(addr_type): [
+ {"action": "permit", "set": {attribute: 120}}
+ ],
+ "rmap_r3_{}".format(addr_type): [
+ {"action": "permit", "set": {attribute: 150}}
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ dut = "r2"
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(
+ tgen, addr_type, dut, input_dict_1, attribute
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_best_path_as_per_bgp_attribute(
+ tgen, addr_type, dut, input_dict_2, attribute
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_within_vrf_to_alter_bgp_attribute_aspath_p0(request):
+ """
+ FUNC_12_e:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of BGP prefixes(IPv4+IPv6) from RED_1 and"
+ " RED_2 in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ "red2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ "blue2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "red2", "blue1", "blue2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to influence BGP parameters - " " Local Preference")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "route_maps": {
+ "rmap_r1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {
+ "path": {"as_num": "111 222", "as_action": "prepend"}
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link1": {}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link1": {}}},
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link2": {}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link2": {}}},
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link3": {}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link3": {}}},
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link4": {}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link4": {}}},
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ dut = "r2"
+ attribute = "path"
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(
+ tgen, addr_type, dut, input_dict_1, attribute
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_best_path_as_per_bgp_attribute(
+ tgen, addr_type, dut, input_dict_2, attribute
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_within_vrf_to_alter_bgp_attribute_lcomm_p0(request):
+ """
+ FUNC_12_f:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of BGP prefixes(IPv4+IPv6) from RED_1 and"
+ " RED_2 in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ "red2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ "blue2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "red2", "blue1", "blue2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to influence BGP parameters - " " Large-community")
+
+ step("Create standard large commumity-list in r2")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r2": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "rmap_lcomm_{}".format(addr_type),
+ "value": "1:1:1 1:2:3 2:1:1 2:2:2",
+ "large": True,
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create route-maps in red1 and r1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "red1": {
+ "route_maps": {
+ "rmap_red1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {
+ "large_community": {"num": "1:1:1 1:2:3 2:1:1 2:2:2"}
+ },
+ }
+ ]
+ }
+ },
+ "r2": {
+ "route_maps": {
+ "rmap_r1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ "large_community_list": {
+ "id": "rmap_lcomm_" + addr_type
+ }
+ },
+ }
+ ]
+ }
+ },
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map in red1")
+
+ input_dict_4 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure neighbor for route map in r2")
+
+ input_dict_4 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "All the prefixes advertised from RED_1 and BLUE_1 should carry"
+ " attributes set by outbound route-maps within specific vrfs. "
+ "Router R1 should be able to match and permit/deny those "
+ "prefixes based on received attributes. Please use below "
+ "commands to verify."
+ )
+
+ input_dict = {
+ "largeCommunity": "1:1:1 1:2:3 2:1:1 2:2:2",
+ }
+
+ for addr_type in ADDR_TYPES:
+ vrf = "RED_A"
+ routes = [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]]
+ result = verify_bgp_community(tgen, addr_type, "r2", routes, input_dict, vrf)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ vrf = "RED_B"
+ routes = [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]]
+ result = verify_bgp_community(tgen, addr_type, "r2", routes, input_dict, vrf)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_match_traffic_based_on_vrf_p0(request):
+ """
+ FUNC_13:
+ Configure a route-map on DUT to match traffic based
+ on a VRF interfaces.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1 "
+ "in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from BLUE_1 in"
+ " vrf instances(BLUE_A and BLUE_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure a route-map on R1 to match the prefixes "
+ "coming from vrf RED_A and set as-prepend to these routes."
+ )
+
+ input_dict_4 = {
+ "r1": {
+ "route_maps": {
+ "ABC": [
+ {
+ "action": "permit",
+ "match": {"source-vrf": "RED_A"},
+ "set": {"path": {"as_num": 1, "as_action": "prepend"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "On R1, import the routes form vrf RED_A and RED_B to BLUE_A and"
+ " apply the route-map under vrf BLUE_A while importing"
+ )
+
+ raw_config = {
+ "r1": {
+ "raw_config": [
+ "router bgp 100 vrf BLUE_A",
+ "address-family ipv4 unicast",
+ "import vrf RED_A",
+ "import vrf RED_B",
+ "import vrf route-map ABC",
+ "address-family ipv6 unicast",
+ "import vrf RED_A",
+ "import vrf RED_B",
+ "import vrf route-map ABC",
+ ]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "All the prefixes advertised from RED_1 and BLUE_1 in vrfs "
+ "RED_B and BLUE_B must prepend the AS number in as-path on R2."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_7 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_vrf_lite_with_static_bgp_originated_routes_p0(request):
+ """
+ FUNC_14:
+ Test VRF-lite with Static+BGP originated routes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from BLUE_1 in"
+ " vrf instances(BLUE_A and BLUE_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK5_1["ipv4"]]
+ + [NETWORK5_2["ipv4"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK5_1["ipv6"]]
+ + [NETWORK5_2["ipv6"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK6_1["ipv4"]]
+ + [NETWORK6_2["ipv4"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK6_1["ipv6"]]
+ + [NETWORK6_2["ipv6"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ },
+ },
+ ]
+ },
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK7_1["ipv4"]]
+ + [NETWORK7_2["ipv4"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK7_1["ipv6"]]
+ + [NETWORK7_2["ipv6"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK8_1["ipv4"]]
+ + [NETWORK8_2["ipv4"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK8_1["ipv6"]]
+ + [NETWORK8_2["ipv6"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Static routes must be installed in associated VRF" " table only.")
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "All the routers must receive advertised as well as "
+ "redistributed(static) prefixes in associated VRF tables."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_prefix_list_to_permit_deny_prefixes_p0(request):
+ """
+ FUNC_15:
+ Configure prefix-lists on DUT and apply to BGP peers to
+ permit/deny prefixes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from BLUE_1 in"
+ " vrf instances(BLUE_A and BLUE_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify routes are present before applying prefix-list")
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On routers RED_1 and BLUE_1, configure prefix-lists to permit"
+ " 4 prefixes and deny 1 prefix x.x.x.5. Apply these in outbound"
+ "direction for each neighbour."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "red1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_red1_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 11,
+ "network": NETWORK2_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 12,
+ "network": NETWORK1_2[addr_type],
+ "action": "deny",
+ },
+ {
+ "seqid": 13,
+ "network": NETWORK2_2[addr_type],
+ "action": "deny",
+ },
+ ]
+ }
+ }
+ },
+ "blue1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_blue1_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 11,
+ "network": NETWORK2_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 12,
+ "network": NETWORK1_2[addr_type],
+ "action": "deny",
+ },
+ {
+ "seqid": 13,
+ "network": NETWORK2_2[addr_type],
+ "action": "deny",
+ },
+ ]
+ }
+ }
+ },
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_r1_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 11,
+ "network": NETWORK2_1[addr_type],
+ "action": "deny",
+ },
+ ]
+ }
+ }
+ },
+ }
+ result = create_prefix_lists(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_5 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_blue1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_blue1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_blue1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_blue1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, each BGP neighbor receives 1"
+ " prefixes in routing table and drops (x.x.x.2)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ permitted_routes = {
+ "red1": {
+ "static_routes": [
+ {"network": [NETWORK1_1[addr_type]], "vrf": "RED_A"},
+ {"network": [NETWORK2_1[addr_type]], "vrf": "RED_B"},
+ ]
+ }
+ }
+
+ denied_routes = {
+ "red1": {
+ "static_routes": [
+ {"network": [NETWORK1_2[addr_type]], "vrf": "RED_A"},
+ {"network": [NETWORK2_2[addr_type]], "vrf": "RED_B"},
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, permitted_routes)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, denied_routes, expected=False)
+ assert result is not True, "Testcase {} : Failed \n"
+ "Expected behaviour: Routes are denied by prefix-list \n"
+ "Error {}".format(tc_name, result)
+
+ step(
+ "On router R1, configure prefix-lists to permit 2 "
+ "prefixes(x.x.x.1-2) and deny 2 prefix(x.x.x.3-4). Apply"
+ " these in inbound direction for each neighbour."
+ )
+
+ input_dict_6 = {
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, each BGP neighbor installs"
+ " only 1 prefix (x.x.x.1)."
+ )
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ permitted_routes = {
+ "red1": {
+ "static_routes": [{"network": [NETWORK1_1[addr_type]], "vrf": "RED_A"}]
+ }
+ }
+
+ denied_routes = {
+ "red1": {
+ "static_routes": [{"network": [NETWORK2_1[addr_type]], "vrf": "RED_A"}]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, permitted_routes)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, denied_routes, expected=False)
+ assert result is not True, "Testcase {} : Failed \n"
+ "Expected behaviour: Routes are denied by prefix-list \n"
+ "Error {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_set_and_match_tag_p0(request):
+ """
+ FUNC_16_1:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 4001,
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 4001,
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to match tag")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "red1": {
+ "route_maps": {
+ "rmap1_{}".format(addr_type): [
+ {"action": "permit", "match": {addr_type: {"tag": "4001"}}}
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ dut = "r1"
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 4001,
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \n"
+ "Error {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_set_and_match_metric_p0(request):
+ """
+ FUNC_16_2:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ },
+ ]
+ },
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to match tag")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r1": {
+ "route_maps": {
+ "rmap1_{}".format(addr_type): [
+ {"action": "permit", "match": {"metric": 123}}
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ dut = "r1"
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \n"
+ "Error {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_set_and_match_community_p0(request):
+ """
+ FUNC_16_3:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Create community-list")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "rmap_lcomm_{}".format(addr_type),
+ "value": "1:1 1:2 1:3 1:4 1:5",
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure a route-maps to match tag")
+
+ step("Create route-maps in red1 and r1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "red1": {
+ "route_maps": {
+ "rmap_red1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {"community": {"num": "1:1 1:2 1:3 1:4 1:5"}},
+ }
+ ]
+ }
+ },
+ "r1": {
+ "route_maps": {
+ "rmap1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "rmap_lcomm_" + addr_type}
+ },
+ }
+ ]
+ }
+ },
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "All the prefixes advertised from RED_1 and BLUE_1 should carry"
+ " attributes set by outbound route-maps within specific vrfs. "
+ "Router R1 should be able to match and permit/deny those "
+ "prefixes based on received attributes. Please use below "
+ "commands to verify."
+ )
+
+ input_dict = {
+ "community": "1:1 1:2 1:3 1:4 1:5",
+ }
+
+ for addr_type in ADDR_TYPES:
+ vrf = "RED_A"
+ routes = [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]]
+ result = verify_bgp_community(tgen, addr_type, "r1", routes, input_dict, vrf)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ vrf = "RED_B"
+ routes = [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]]
+ result = verify_bgp_community(tgen, addr_type, "r1", routes, input_dict, vrf)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_multi_vrf_topo2/bgp_multi_vrf_topo2.json b/tests/topotests/bgp_multi_vrf_topo2/bgp_multi_vrf_topo2.json
new file mode 100644
index 0000000000..ab570fcc16
--- /dev/null
+++ b/tests/topotests/bgp_multi_vrf_topo2/bgp_multi_vrf_topo2.json
@@ -0,0 +1,1277 @@
+{
+ "address_types": ["ipv4","ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "red1": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "blue1": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE_A",
+ "id": "1"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r1": {
+ "links": {
+ "red1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "red1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "blue1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "blue1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r4-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r4-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r4-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link1":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link1":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link2":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link2":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link3":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link3":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link4":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link4":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r2": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r1-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r4-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r4-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r4-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "red2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "red2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "blue2-link1": {"ipv4": "auto", "ipv6": "autor3", "vrf": "BLUE_A"},
+ "blue2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link3": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link4": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r4": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r1-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "red2": {
+ "links": {
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "blue2": {
+ "links": {
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE_A",
+ "id": "1"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
new file mode 100755
index 0000000000..27c4430a52
--- /dev/null
+++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
@@ -0,0 +1,2012 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2020 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Following tests are covered to test BGP Multi-VRF:
+
+CHAOS_1:
+ Do a shut and no shut on connecting interface of DUT,
+ to see if all vrf instances clear their respective BGP tables
+ during the interface down and restores when interface brought
+kCHAOS_3:
+ VRF leaking - next-hop interface is flapping.
+CHAOS_5:
+ VRF - VLANs - Routing Table ID - combination testcase
+ on DUT.
+CHAOS_9:
+ Verify that all vrf instances fall back
+ to backup path, if primary link goes down.
+
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+from copy import deepcopy
+from time import sleep
+
+
+# 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 mininet.topo import Topo
+
+from lib.common_config import (
+ step,
+ verify_rib,
+ start_topology,
+ write_test_header,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_route_maps,
+ shutdown_bringup_interface,
+ start_router_daemons,
+ kill_router_daemons,
+ create_static_routes,
+ create_vrf_cfg,
+ create_interfaces_cfg,
+ create_interface_in_kernel,
+ kill_mininet_routers_process,
+ get_frr_ipv6_linklocal,
+ check_router_status,
+ apply_raw_config,
+)
+
+from lib.topolog import logger
+from lib.bgp import clear_bgp, verify_bgp_rib, create_router_bgp, verify_bgp_convergence
+from lib.topojson import build_config_from_json, build_topo_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/bgp_multi_vrf_topo2.json".format(CWD)
+
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ assert False, "Could not read file {}".format(jsonFile)
+
+# Global variables
+NETWORK1_1 = {"ipv4": "1.1.1.1/32", "ipv6": "1::1/128"}
+NETWORK1_2 = {"ipv4": "1.1.1.2/32", "ipv6": "1::2/128"}
+NETWORK2_1 = {"ipv4": "2.1.1.1/32", "ipv6": "2::1/128"}
+NETWORK2_2 = {"ipv4": "2.1.1.2/32", "ipv6": "2::2/128"}
+NETWORK3_1 = {"ipv4": "3.1.1.1/32", "ipv6": "3::1/128"}
+NETWORK3_2 = {"ipv4": "3.1.1.2/32", "ipv6": "3::2/128"}
+NETWORK4_1 = {"ipv4": "4.1.1.1/32", "ipv6": "4::1/128"}
+NETWORK4_2 = {"ipv4": "4.1.1.2/32", "ipv6": "4::2/128"}
+NETWORK9_1 = {"ipv4": "100.1.0.1/30", "ipv6": "100::1/126"}
+NETWORK9_2 = {"ipv4": "100.1.0.2/30", "ipv6": "100::2/126"}
+
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+LOOPBACK_2 = {
+ "ipv4": "20.20.20.20/32",
+ "ipv6": "20::20:20/128",
+ "ipv4_mask": "255.255.255.255",
+ "ipv6_mask": None,
+}
+
+MAX_PATHS = 2
+KEEPALIVETIMER = 1
+HOLDDOWNTIMER = 3
+PREFERRED_NEXT_HOP = "link_local"
+
+
+class CreateTopo(Topo):
+ """
+ Test BasicTopo - topology 1
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ """Build function"""
+ tgen = get_topogen(self)
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Kill stale mininet routers and process
+ kill_mininet_routers_process(tgen)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ global BGP_CONVERGENCE
+ global ADDR_TYPES
+ 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
+ )
+
+ 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)
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_vrf_with_multiple_links_p1(request):
+ """
+ CHAOS_9:
+ Verify that all vrf instances fall back
+ to backup path, if primary link goes down.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure BGP neighborships(IPv4+IPv6) between R1 and R4 "
+ "using exact same link IPs for all 4 VRFs."
+ )
+
+ topo_modify = deepcopy(topo)
+ build_config_from_json(tgen, topo_modify)
+
+ interfaces = ["link1", "link2", "link3", "link4"]
+ for interface in interfaces:
+ topo_modify["routers"]["r1"]["links"]["r4-{}".format(interface)][
+ "delete"
+ ] = True
+ topo_modify["routers"]["r4"]["links"]["r1-{}".format(interface)][
+ "delete"
+ ] = True
+
+ step("Build interface config from json")
+ create_interfaces_cfg(tgen, topo_modify["routers"])
+
+ interfaces = ["link1", "link2", "link3", "link4"]
+ for interface in interfaces:
+ del topo_modify["routers"]["r1"]["links"]["r4-{}".format(interface)]["delete"]
+ del topo_modify["routers"]["r4"]["links"]["r1-{}".format(interface)]["delete"]
+
+ r1_config = []
+ r4_config = []
+ for addr_type in ADDR_TYPES:
+ interfaces = ["link1", "link2", "link3", "link4"]
+ for interface in interfaces:
+ intf_name_r1 = topo_modify["routers"]["r1"]["links"][
+ "r4-{}".format(interface)
+ ]["interface"]
+ topo_modify["routers"]["r1"]["links"]["r4-{}".format(interface)][
+ addr_type
+ ] = NETWORK9_1[addr_type]
+
+ intf_name_r4 = topo_modify["routers"]["r4"]["links"][
+ "r1-{}".format(interface)
+ ]["interface"]
+ topo_modify["routers"]["r4"]["links"]["r1-{}".format(interface)][
+ addr_type
+ ] = NETWORK9_2[addr_type]
+
+ r1_config.append("interface {}".format(intf_name_r1))
+ r4_config.append("interface {}".format(intf_name_r4))
+ if addr_type == "ipv4":
+ r1_config.append("no ip address {}".format(NETWORK9_1[addr_type]))
+ r4_config.append("no ip address {}".format(NETWORK9_2[addr_type]))
+ else:
+ r1_config.append("no ipv6 address {}".format(NETWORK9_1[addr_type]))
+ r4_config.append("no ipv6 address {}".format(NETWORK9_2[addr_type]))
+
+ step("Build interface config from json")
+ create_interfaces_cfg(tgen, topo_modify["routers"])
+
+ step("Create bgp config")
+ result = create_router_bgp(tgen, topo_modify["routers"])
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify BGP convergence")
+
+ result = verify_bgp_convergence(tgen, topo_modify)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ step(
+ "Advertise below prefixes in BGP using static redistribution"
+ " for both vrfs (RED_A and BLUE_A) on router R2.."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["r1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "RED_B", "BLUE_A", "BLUE_B"]
+ AS_NUM = [100, 100, 100, 100]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo_modify, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify routes are installed with same nexthop in different" " VRFs")
+
+ for addr_type in ADDR_TYPES:
+ dut = "r4"
+ _input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R1_NEXTHOP = topo_modify["routers"]["r1"]["links"]["r4-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, _input_dict, next_hop=R1_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ _input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R1_NEXTHOP = topo_modify["routers"]["r1"]["links"]["r4-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, _input_dict, next_hop=R1_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ _input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ }
+ ]
+ }
+ }
+
+ R1_NEXTHOP = topo_modify["routers"]["r1"]["links"]["r4-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, _input_dict, next_hop=R1_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ _input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ }
+ ]
+ }
+ }
+
+ R1_NEXTHOP = topo_modify["routers"]["r1"]["links"]["r4-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, _input_dict, next_hop=R1_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure a route-map on R3 to prepend as-path and apply"
+ " for neighbour router R2 in both vrfs, in inbound direction."
+ )
+
+ input_dict_4 = {
+ "r3": {
+ "route_maps": {
+ "ASP": [
+ {
+ "action": "permit",
+ "set": {"path": {"as_num": 123, "as_action": "prepend"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Apply route-map to neighbours")
+ step(
+ "Configure ECMP on router R3 using 'max-path' command for both"
+ " VRFs RED_A and BLUE_A."
+ )
+
+ input_dict_5 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo_modify, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ peer = "r2"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ intf = topo_modify["routers"][peer]["links"]["r3-link1"]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ R2_NEXTHOP = get_frr_ipv6_linklocal(tgen, peer, intf=intf, vrf="RED_A")
+ else:
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link1"][
+ addr_type
+ ].split("/")[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ intf = topo["routers"][peer]["links"]["r3-link3"]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ R2_NEXTHOP = get_frr_ipv6_linklocal(tgen, peer, intf=intf, vrf="BLUE_A")
+ else:
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link3"][
+ addr_type
+ ].split("/")[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure ECMP on router R3 using max-path command for"
+ " both VRFs RED_A and BLUE_A."
+ )
+
+ input_dict_7 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo_modify, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("R3 should install prefixes from both next-hops (R2 and R4)")
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ peer = "r2"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ intf = topo_modify["routers"][peer]["links"]["r3-link1"]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ R2_NEXTHOP = get_frr_ipv6_linklocal(tgen, peer, intf=intf, vrf="RED_A")
+ else:
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link1"][
+ addr_type
+ ].split("/")[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ intf = topo_modify["routers"][peer]["links"]["r3-link3"]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ R2_NEXTHOP = get_frr_ipv6_linklocal(tgen, peer, intf=intf, vrf="BLUE_A")
+ else:
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link3"][
+ addr_type
+ ].split("/")[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Shutdown interface between R2 and R3 for vrfs RED_A and " "BLUE_A.")
+
+ intf1 = topo_modify["routers"]["r2"]["links"]["r3-link1"]["interface"]
+ intf2 = topo_modify["routers"]["r2"]["links"]["r3-link3"]["interface"]
+
+ interfaces = [intf1, intf2]
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r2", intf, False)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ peer = "r4"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link3"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Unshut the interfaces between R2 and R3 for vrfs RED_A and BLUE_A.")
+
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r2", intf, True)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ peer = "r2"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link3"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Remove route-map from R3 for vrfs RED_A and BLUE_A.")
+
+ input_dict_6 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv4",
+ "direction": "in",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv6",
+ "direction": "in",
+ "delete": True,
+ },
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv4",
+ "direction": "in",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv6",
+ "direction": "in",
+ "delete": True,
+ },
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo_modify, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link3"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Shutdown links between between R2 and R3 for vrfs RED_A and" " BLUE_A.")
+
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r2", intf, False)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link3"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Bringup links between between R2 and R3 for vrfs RED_A and" " BLUE_A.")
+
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r2", intf, True)
+
+ step("Deleting manualy assigned ip address from router r1 and r4 interfaces")
+ raw_config = {"r1": {"raw_config": r1_config}, "r4": {"raw_config": r4_config}}
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_shut_noshut_p1(request):
+ """
+ CHAOS_1:
+ Do a shut and no shut on connecting interface of DUT,
+ to see if all vrf instances clear their respective BGP tables
+ during the interface down and restores when interface brought
+ back up again.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Build interface config from json")
+ create_interfaces_cfg(tgen, topo["routers"])
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step(
+ "Advertise unique prefixes in BGP using static redistribution"
+ " for both vrfs (RED_A and RED_B) on router RED_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique prefixes in BGP using static redistribution"
+ " for both vrfs (BLUE_A and BLUE_B) on router BLUE_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Api call to modfiy BGP timerse")
+
+ input_dict_4 = {
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link2": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link2": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link4": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link4": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r1", vrf=["RED_A", "RED_B", "BLUE_A", "BLUE_B"])
+
+ clear_bgp(tgen, addr_type, "r2", vrf=["RED_A", "RED_B", "BLUE_A", "BLUE_B"])
+
+ step("Shut down connecting interface between R1<<>>R2 on R1.")
+ step("Repeat step-3 and step-4 10 times.")
+
+ for count in range(1, 2):
+ step("Iteration {}".format(count))
+ step("Shut down connecting interface between R1<<>>R2 on R1.")
+
+ intf1 = topo["routers"]["r1"]["links"]["r2-link1"]["interface"]
+ intf2 = topo["routers"]["r1"]["links"]["r2-link2"]["interface"]
+ intf3 = topo["routers"]["r1"]["links"]["r2-link3"]["interface"]
+ intf4 = topo["routers"]["r1"]["links"]["r2-link4"]["interface"]
+
+ interfaces = [intf1, intf2, intf3, intf4]
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r1", intf, False)
+
+ step(
+ "On R2, all BGP peering in respective vrf instances go down"
+ " when the interface is shut"
+ )
+
+ step("Sleeping for holddowntimer+1 sec..")
+ sleep(HOLDDOWNTIMER + 1)
+
+ result = verify_bgp_convergence(tgen, topo, expected=False)
+ assert result is not True, "Testcase {} : Failed \n "
+ "Expected Behaviour: BGP will not be converged \n "
+ "Error {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]]
+ + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]]
+ + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]]
+ + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]]
+ + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n "
+ " Expected Behaviour: Routes are flushed out \n "
+ "Error {}".format(tc_name, result)
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert result is not True, "Testcase {} : Failed \n "
+ " Expected Behaviour: Routes are flushed out \n "
+ "Error {}".format(tc_name, result)
+
+ step("Bring up connecting interface between R1<<>>R2 on R1.")
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r1", intf, True)
+
+ step(
+ "R2 restores BGP peering and routing tables in all vrf "
+ "instances when interface brought back up again"
+ )
+
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]]
+ + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]]
+ + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]]
+ + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]]
+ + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_vrf_vlan_routing_table_p1(request):
+ """
+ CHAOS_5:
+ VRF - VLANs - Routing Table ID - combination testcase
+ on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique prefixes(IPv4+IPv6) in BGP using"
+ " network command for vrf RED_A on router R2"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes(IPv4+IPv6) is overridden and doesn't"
+ " have duplicate entries within VRF RED_A on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Api call to modfiy BGP timerse")
+
+ input_dict_4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r3", vrf=["RED_A"])
+
+ step("Repeat for 5 times.")
+
+ for count in range(1, 2):
+ step("Iteration {}..".format(count))
+ step("Delete a specific VRF instance(RED_A) from router R3")
+
+ input_dict = {"r3": {"vrfs": [{"name": "RED_A", "id": "1", "delete": True}]}}
+
+ result = create_vrf_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Sleeping for holdowntimer+1 sec..")
+ sleep(HOLDDOWNTIMER + 1)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are"
+ " cleaned \n Error {}".format(tc_name, result)
+
+ step("Add/reconfigure the same VRF instance again")
+
+ result = create_vrf_cfg(tgen, {"r3": topo["routers"]["r3"]})
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After deleting VRFs ipv6 addresses wil be deleted from kernel "
+ " Adding back ipv6 addresses"
+ )
+
+ dut = "r3"
+ vrf = "RED_A"
+
+ for c_link, c_data in topo["routers"][dut]["links"].items():
+ if c_data["vrf"] != vrf:
+ continue
+
+ intf_name = c_data["interface"]
+ intf_ipv6 = c_data["ipv6"]
+
+ create_interface_in_kernel(
+ tgen, dut, intf_name, intf_ipv6, vrf, create=False
+ )
+
+ step("Sleeping for holdowntimer+1 sec..")
+ sleep(HOLDDOWNTIMER + 1)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_vrf_route_leaking_next_hop_interface_flapping_p1(request):
+ """
+ CHAOS_3:
+ VRF leaking - next-hop interface is flapping.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Create loopback interface")
+
+ for addr_type in ADDR_TYPES:
+ create_interface_in_kernel(
+ tgen,
+ "red1",
+ "loopback2",
+ LOOPBACK_2[addr_type],
+ "RED_B",
+ LOOPBACK_2["{}_mask".format(addr_type)],
+ )
+
+ intf_red1_r11 = topo["routers"]["red1"]["links"]["r1-link2"]["interface"]
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("VRF RED_A should install a route for vrf RED_B's " "loopback ip.")
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Repeat step-2 to 4 at least 5 times")
+
+ for count in range(1, 2):
+ intf1 = topo["routers"]["red1"]["links"]["r1-link2"]["interface"]
+
+ step(
+ "Iteration {}: Shutdown interface {} on router"
+ "RED_1.".format(count, intf1)
+ )
+ shutdown_bringup_interface(tgen, "red1", intf1, False)
+
+ step("Verify that RED_A removes static route from routing " "table.")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_1, protocol="static", expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected Behaviour: Routes are"
+ " not present Error {}".format(tc_name, result)
+ )
+
+ step("Bring up interface {} on router RED_1 again.".format(intf1))
+ shutdown_bringup_interface(tgen, "red1", intf1, True)
+
+ step(
+ "Verify that RED_A reinstalls static route pointing to "
+ "RED_B's IP in routing table again"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 2dd90e9a86..69c807f300 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -75,8 +75,12 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False, load_config=True
"address_family": {
"ipv4": {
"unicast": {
- "redistribute": [
- {"redist_type": "static"},
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "metric" : 123
+ }
+ },
{"redist_type": "connected"}
],
"advertise_networks": [
@@ -143,50 +147,55 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False, load_config=True
logger.debug("Router %s: 'bgp' not present in input_dict", router)
continue
- data_all_bgp = __create_bgp_global(tgen, input_dict, router, build)
- if data_all_bgp:
- bgp_data = input_dict[router]["bgp"]
+ bgp_data_list = input_dict[router]["bgp"]
- bgp_addr_data = bgp_data.setdefault("address_family", {})
+ if type(bgp_data_list) is not list:
+ bgp_data_list = [bgp_data_list]
- if not bgp_addr_data:
- logger.debug(
- "Router %s: 'address_family' not present in " "input_dict for BGP",
- router,
- )
- else:
+ for bgp_data in bgp_data_list:
+ data_all_bgp = __create_bgp_global(tgen, bgp_data, router, build)
+ if data_all_bgp:
+ bgp_addr_data = bgp_data.setdefault("address_family", {})
- ipv4_data = bgp_addr_data.setdefault("ipv4", {})
- ipv6_data = bgp_addr_data.setdefault("ipv6", {})
+ if not bgp_addr_data:
+ logger.debug(
+ "Router %s: 'address_family' not present in "
+ "input_dict for BGP",
+ router,
+ )
+ else:
- neigh_unicast = (
- True
- if ipv4_data.setdefault("unicast", {})
- or ipv6_data.setdefault("unicast", {})
- else False
- )
+ ipv4_data = bgp_addr_data.setdefault("ipv4", {})
+ ipv6_data = bgp_addr_data.setdefault("ipv6", {})
- if neigh_unicast:
- data_all_bgp = __create_bgp_unicast_neighbor(
- tgen,
- topo,
- input_dict,
- router,
- afi_test,
- config_data=data_all_bgp,
+ neigh_unicast = (
+ True
+ if ipv4_data.setdefault("unicast", {})
+ or ipv6_data.setdefault("unicast", {})
+ else False
)
- try:
- result = create_common_configuration(
- tgen, router, data_all_bgp, "bgp", build, load_config
- )
- except InvalidCLIError:
- # Traceback
- errormsg = traceback.format_exc()
- logger.error(errormsg)
- return errormsg
+ if neigh_unicast:
+ data_all_bgp = __create_bgp_unicast_neighbor(
+ tgen,
+ topo,
+ bgp_data,
+ router,
+ afi_test,
+ config_data=data_all_bgp,
+ )
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ try:
+ result = create_common_configuration(
+ tgen, router, data_all_bgp, "bgp", build, load_config
+ )
+ except InvalidCLIError:
+ # Traceback
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: create_router_bgp()")
return result
@@ -206,19 +215,16 @@ def __create_bgp_global(tgen, input_dict, router, build=False):
True or False
"""
+ result = False
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- bgp_data = input_dict[router]["bgp"]
+ bgp_data = input_dict
del_bgp_action = bgp_data.setdefault("delete", False)
- if del_bgp_action:
- config_data = ["no router bgp"]
-
- return config_data
config_data = []
if "local_as" not in bgp_data and build:
- logger.error(
+ logger.debug(
"Router %s: 'local_as' not present in input_dict" "for BGP", router
)
return False
@@ -229,6 +235,12 @@ def __create_bgp_global(tgen, input_dict, router, build=False):
if vrf_id:
cmd = "{} vrf {}".format(cmd, vrf_id)
+ if del_bgp_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ return config_data
+
config_data.append(cmd)
config_data.append("no bgp ebgp-requires-policy")
@@ -325,12 +337,15 @@ def __create_bgp_unicast_neighbor(
* `build` : Only for initial setup phase this is set as True.
"""
+ result = False
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
add_neigh = True
+ bgp_data = input_dict
if "router bgp" in config_data:
add_neigh = False
- bgp_data = input_dict[router]["bgp"]["address_family"]
+
+ bgp_data = input_dict["address_family"]
for addr_type, addr_dict in bgp_data.iteritems():
if not addr_dict:
@@ -403,14 +418,19 @@ def __create_bgp_unicast_neighbor(
if redistribute_data:
for redistribute in redistribute_data:
if "redist_type" not in redistribute:
- logger.error(
+ logger.debug(
"Router %s: 'redist_type' not present in " "input_dict", router
)
else:
cmd = "redistribute {}".format(redistribute["redist_type"])
redist_attr = redistribute.setdefault("attribute", None)
if redist_attr:
- cmd = "{} {}".format(cmd, redist_attr)
+ if isinstance(redist_attr, dict):
+ for key, value in redist_attr.items():
+ cmd = "{} {} {}".format(cmd, key, value)
+ else:
+ cmd = "{} {}".format(cmd, redist_attr)
+
del_action = redistribute.setdefault("delete", False)
if del_action:
cmd = "no {}".format(cmd)
@@ -453,13 +473,18 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
config_data = []
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- bgp_data = input_dict[router]["bgp"]["address_family"]
+ bgp_data = input_dict["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
for name, peer_dict in neigh_data.iteritems():
for dest_link, peer in peer_dict["dest_link"].iteritems():
nh_details = topo[name]
- remote_as = nh_details["bgp"]["local_as"]
+
+ if "vrfs" in topo[router]:
+ remote_as = nh_details["bgp"][0]["local_as"]
+ else:
+ remote_as = nh_details["bgp"]["local_as"]
+
update_source = None
if dest_link in nh_details["links"].keys():
@@ -549,7 +574,7 @@ def __create_bgp_unicast_address_family(
config_data = []
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- bgp_data = input_dict[router]["bgp"]["address_family"]
+ bgp_data = input_dict["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
for peer_name, peer_dict in deepcopy(neigh_data).iteritems():
@@ -605,8 +630,12 @@ def __create_bgp_unicast_address_family(
allowas_in = peer.setdefault("allowas-in", None)
# next-hop-self
- if next_hop_self:
- config_data.append("{} next-hop-self".format(neigh_cxt))
+ if next_hop_self is not None:
+ if next_hop_self is True:
+ config_data.append("{} next-hop-self".format(neigh_cxt))
+ else:
+ config_data.append("no {} next-hop-self".format(neigh_cxt))
+
# send_community
if send_community:
config_data.append("{} send-community".format(neigh_cxt))
@@ -840,77 +869,288 @@ def verify_router_id(tgen, topo, input_dict):
@retry(attempts=20, wait=2, return_is_str=True)
-def verify_bgp_convergence(tgen, topo):
+def verify_bgp_convergence(tgen, topo, dut=None):
"""
API will verify if BGP is converged with in the given time frame.
Running "show bgp summary json" command and verify bgp neighbor
state is established,
+
Parameters
----------
* `tgen`: topogen object
* `topo`: input json file data
- * `addr_type`: ip_type, ipv4/ipv6
+ * `dut`: device under test
+
Usage
-----
# To veriry is BGP is converged for all the routers used in
topology
- results = verify_bgp_convergence(tgen, topo, "ipv4")
+ results = verify_bgp_convergence(tgen, topo, dut="r1")
+
Returns
-------
errormsg(str) or True
"""
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ logger.debug("Entering lib API: verify_bgp_convergence()")
for router, rnode in tgen.routers().iteritems():
if "bgp" not in topo["routers"][router]:
continue
- logger.info("Verifying BGP Convergence on router %s", router)
- show_bgp_json = run_frr_cmd(rnode, "show bgp summary json", isjson=True)
+ if dut is not None and dut != router:
+ continue
+
+ logger.info("Verifying BGP Convergence on router %s:", router)
+ show_bgp_json = run_frr_cmd(rnode, "show bgp vrf all summary json", isjson=True)
# Verifying output dictionary show_bgp_json is empty or not
if not bool(show_bgp_json):
errormsg = "BGP is not running"
return errormsg
# To find neighbor ip type
- bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
- for addr_type in bgp_addr_type.keys():
- if not check_address_types(addr_type):
- continue
- total_peer = 0
+ bgp_data_list = topo["routers"][router]["bgp"]
- bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+ if type(bgp_data_list) is not list:
+ bgp_data_list = [bgp_data_list]
- for bgp_neighbor in bgp_neighbors:
- total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"])
+ for bgp_data in bgp_data_list:
+ if "vrf" in bgp_data:
+ vrf = bgp_data["vrf"]
+ if vrf is None:
+ vrf = "default"
+ else:
+ vrf = "default"
- for addr_type in bgp_addr_type.keys():
- if not check_address_types(addr_type):
- continue
- bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+ # To find neighbor ip type
+ bgp_addr_type = bgp_data["address_family"]
+ if "l2vpn" in bgp_addr_type:
+ total_evpn_peer = 0
- no_of_peer = 0
- for bgp_neighbor, peer_data in bgp_neighbors.iteritems():
- for dest_link in peer_data["dest_link"].keys():
- data = topo["routers"][bgp_neighbor]["links"]
- if dest_link in data:
- neighbor_ip = data[dest_link][addr_type].split("/")[0]
- if addr_type == "ipv4":
- ipv4_data = show_bgp_json["ipv4Unicast"]["peers"]
- nh_state = ipv4_data[neighbor_ip]["state"]
- else:
- ipv6_data = show_bgp_json["ipv6Unicast"]["peers"]
- nh_state = ipv6_data[neighbor_ip]["state"]
+ if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
+ continue
- if nh_state == "Established":
- no_of_peer += 1
- if no_of_peer == total_peer:
- logger.info("BGP is Converged for router %s", router)
+ bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"]
+ total_evpn_peer += len(bgp_neighbors)
+
+ no_of_evpn_peer = 0
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for _addr_type, dest_link_dict in peer_data.items():
+ data = topo["routers"][bgp_neighbor]["links"]
+ for dest_link in dest_link_dict.keys():
+ if dest_link in data:
+ peer_details = peer_data[_addr_type][dest_link]
+
+ neighbor_ip = data[dest_link][_addr_type].split("/")[0]
+ nh_state = None
+
+ if (
+ "ipv4Unicast" in show_bgp_json[vrf]
+ or "ipv6Unicast" in show_bgp_json[vrf]
+ ):
+ errormsg = (
+ "[DUT: %s] VRF: %s, "
+ "ipv4Unicast/ipv6Unicast"
+ " address-family present"
+ " under l2vpn" % (router, vrf)
+ )
+ return errormsg
+
+ l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
+ "peers"
+ ]
+ nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
+
+ if nh_state == "Established":
+ no_of_evpn_peer += 1
+
+ if no_of_evpn_peer == total_evpn_peer:
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
+ router,
+ vrf,
+ )
+ else:
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged "
+ "for evpn peers" % (router, vrf)
+ )
+ return errormsg
+ else:
+ for addr_type in bgp_addr_type.keys():
+ if not check_address_types(addr_type):
+ continue
+ total_peer = 0
+
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ for bgp_neighbor in bgp_neighbors:
+ total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"])
+
+ for addr_type in bgp_addr_type.keys():
+ if not check_address_types(addr_type):
+ continue
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ no_of_peer = 0
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for dest_link in peer_data["dest_link"].keys():
+ data = topo["routers"][bgp_neighbor]["links"]
+ if dest_link in data:
+ peer_details = peer_data["dest_link"][dest_link]
+ # for link local neighbors
+ if (
+ "neighbor_type" in peer_details
+ and peer_details["neighbor_type"] == "link-local"
+ ):
+ neighbor_ip = get_ipv6_linklocal_address(
+ topo["routers"], bgp_neighbor, dest_link
+ )
+ elif "source_link" in peer_details:
+ neighbor_ip = topo["routers"][bgp_neighbor][
+ "links"
+ ][peer_details["source_link"]][addr_type].split(
+ "/"
+ )[
+ 0
+ ]
+ elif (
+ "neighbor_type" in peer_details
+ and peer_details["neighbor_type"] == "unnumbered"
+ ):
+ neighbor_ip = data[dest_link]["peer-interface"]
+ else:
+ neighbor_ip = data[dest_link][addr_type].split("/")[
+ 0
+ ]
+ nh_state = None
+
+ if addr_type == "ipv4":
+ ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
+ "peers"
+ ]
+ nh_state = ipv4_data[neighbor_ip]["state"]
+ else:
+ ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
+ "peers"
+ ]
+ nh_state = ipv6_data[neighbor_ip]["state"]
+
+ if nh_state == "Established":
+ no_of_peer += 1
+
+ if no_of_peer == total_peer:
+ logger.info("[DUT: %s] VRF: %s, BGP is Converged", router, vrf)
+ else:
+ errormsg = "[DUT: %s] VRF: %s, BGP is not converged" % (router, vrf)
+ return errormsg
+
+ logger.debug("Exiting API: verify_bgp_convergence()")
+ return True
+
+
+@retry(attempts=3, wait=4, return_is_str=True)
+def verify_bgp_community(
+ tgen, addr_type, router, network, input_dict=None, vrf=None, bestpath=False
+):
+ """
+ API to veiryf BGP large community is attached in route for any given
+ DUT by running "show bgp ipv4/6 {route address} json" command.
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test
+ * `network`: network for which set criteria needs to be verified
+ * `input_dict`: having details like - for which router, community and
+ values needs to be verified
+ * `vrf`: VRF name
+ * `bestpath`: To check best path cli
+
+ Usage
+ -----
+ networks = ["200.50.2.0/32"]
+ input_dict = {
+ "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ result = verify_bgp_community(tgen, "ipv4", dut, network, input_dict=None)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: verify_bgp_community()")
+ if router not in tgen.routers():
+ return False
+
+ rnode = tgen.routers()[router]
+
+ logger.info(
+ "Verifying BGP community attributes on dut %s: for %s " "network %s",
+ router,
+ addr_type,
+ network,
+ )
+
+ command = "show bgp"
+
+ sleep(5)
+ for net in network:
+ if vrf:
+ cmd = "{} vrf {} {} {} json".format(command, vrf, addr_type, net)
+ elif bestpath:
+ cmd = "{} {} {} bestpath json".format(command, addr_type, net)
else:
- errormsg = "BGP is not converged for router {}".format(router)
+ cmd = "{} {} {} json".format(command, addr_type, net)
+
+ show_bgp_json = run_frr_cmd(rnode, cmd, isjson=True)
+ if "paths" not in show_bgp_json:
+ return "Prefix {} not found in BGP table of router: {}".format(net, router)
+
+ as_paths = show_bgp_json["paths"]
+ found = False
+ for i in range(len(as_paths)):
+ if (
+ "largeCommunity" in show_bgp_json["paths"][i]
+ or "community" in show_bgp_json["paths"][i]
+ ):
+ found = True
+ logger.info(
+ "Large Community attribute is found for route:" " %s in router: %s",
+ net,
+ router,
+ )
+ if input_dict is not None:
+ for criteria, comm_val in input_dict.items():
+ show_val = show_bgp_json["paths"][i][criteria]["string"]
+ if comm_val == show_val:
+ logger.info(
+ "Verifying BGP %s for prefix: %s"
+ " in router: %s, found expected"
+ " value: %s",
+ criteria,
+ net,
+ router,
+ comm_val,
+ )
+ else:
+ errormsg = (
+ "Failed: Verifying BGP attribute"
+ " {} for route: {} in router: {}"
+ ", expected value: {} but found"
+ ": {}".format(criteria, net, router, comm_val, show_val)
+ )
+ return errormsg
+
+ if not found:
+ errormsg = (
+ "Large Community attribute is not found for route: "
+ "{} in router: {} ".format(net, router)
+ )
return errormsg
- logger.debug("Exiting API: verify_bgp_convergence()")
+ logger.debug("Exiting lib API: verify_bgp_community()")
return True
@@ -1090,6 +1330,7 @@ def clear_bgp(tgen, addr_type, router, vrf=None):
"""
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
if router not in tgen.routers():
return False
@@ -1102,9 +1343,21 @@ def clear_bgp(tgen, addr_type, router, vrf=None):
# Clearing BGP
logger.info("Clearing BGP neighborship for router %s..", router)
if addr_type == "ipv4":
- run_frr_cmd(rnode, "clear ip bgp *")
+ if vrf:
+ for _vrf in vrf:
+ run_frr_cmd(rnode, "clear ip bgp vrf {} *".format(_vrf))
+ else:
+ run_frr_cmd(rnode, "clear ip bgp *")
elif addr_type == "ipv6":
- run_frr_cmd(rnode, "clear bgp ipv6 *")
+ if vrf:
+ for _vrf in vrf:
+ run_frr_cmd(rnode, "clear bgp vrf {} ipv6 *".format(_vrf))
+ else:
+ run_frr_cmd(rnode, "clear bgp ipv6 *")
+ else:
+ run_frr_cmd(rnode, "clear bgp *")
+
+ sleep(5)
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
@@ -1698,7 +1951,6 @@ def verify_best_path_as_per_bgp_attribute(
"show bgp ipv4/6 json" command will be run and verify best path according
to shortest as-path, highest local-preference and med, lowest weight and
route origin IGP>EGP>INCOMPLETE.
-
Parameters
----------
* `tgen` : topogen object
@@ -1707,7 +1959,6 @@ def verify_best_path_as_per_bgp_attribute(
* `attribute` : calculate best path using this attribute
* `input_dict`: defines different routes to calculate for which route
best path is selected
-
Usage
-----
# To verify best path for routes 200.50.2.0/32 and 200.60.2.0/32 from
@@ -1741,114 +1992,155 @@ def verify_best_path_as_per_bgp_attribute(
"""
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
if router not in tgen.routers():
return False
rnode = tgen.routers()[router]
- command = "show bgp {} json".format(addr_type)
+ # Verifying show bgp json
+ command = "show bgp"
- sleep(5)
+ sleep(2)
logger.info("Verifying router %s RIB for best path:", router)
- sh_ip_bgp_json = run_frr_cmd(rnode, command, isjson=True)
+ static_route = False
+ advertise_network = False
for route_val in input_dict.values():
- net_data = route_val["bgp"]["address_family"][addr_type]["unicast"]
- networks = net_data["advertise_networks"]
- for network in networks:
- route = network["network"]
+ if "static_routes" in route_val:
+ static_route = True
+ networks = route_val["static_routes"]
+ else:
+ advertise_network = True
+ net_data = route_val["bgp"]["address_family"][addr_type]["unicast"]
+ networks = net_data["advertise_networks"]
- route_attributes = sh_ip_bgp_json["routes"][route]
- _next_hop = None
- compare = None
- attribute_dict = {}
- for route_attribute in route_attributes:
- next_hops = route_attribute["nexthops"]
- for next_hop in next_hops:
- next_hop_ip = next_hop["ip"]
- attribute_dict[next_hop_ip] = route_attribute[attribute]
+ for network in networks:
+ _network = network["network"]
+ no_of_ip = network.setdefault("no_of_ip", 1)
+ vrf = network.setdefault("vrf", None)
- # AS_PATH attribute
- if attribute == "path":
- # Find next_hop for the route have minimum as_path
- _next_hop = min(
- attribute_dict, key=lambda x: len(set(attribute_dict[x]))
- )
- compare = "SHORTEST"
-
- # LOCAL_PREF attribute
- elif attribute == "locPrf":
- # Find next_hop for the route have highest local preference
- _next_hop = max(attribute_dict, key=(lambda k: attribute_dict[k]))
- compare = "HIGHEST"
-
- # WEIGHT attribute
- elif attribute == "weight":
- # Find next_hop for the route have highest weight
- _next_hop = max(attribute_dict, key=(lambda k: attribute_dict[k]))
- compare = "HIGHEST"
-
- # ORIGIN attribute
- elif attribute == "origin":
- # Find next_hop for the route have IGP as origin, -
- # - rule is IGP>EGP>INCOMPLETE
- _next_hop = [
- key for (key, value) in attribute_dict.iteritems() if value == "IGP"
- ][0]
- compare = ""
-
- # MED attribute
- elif attribute == "metric":
- # Find next_hop for the route have LOWEST MED
- _next_hop = min(attribute_dict, key=(lambda k: attribute_dict[k]))
- compare = "LOWEST"
-
- # Show ip route
- if addr_type == "ipv4":
- command = "show ip route json"
+ if vrf:
+ cmd = "{} vrf {}".format(command, vrf)
else:
- command = "show ipv6 route json"
+ cmd = command
+
+ cmd = "{} {}".format(cmd, addr_type)
+ cmd = "{} json".format(cmd)
+ sh_ip_bgp_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ routes = generate_ips(_network, no_of_ip)
+ for route in routes:
+ route = str(ipaddr.IPNetwork(unicode(route)))
+
+ if route in sh_ip_bgp_json["routes"]:
+ route_attributes = sh_ip_bgp_json["routes"][route]
+ _next_hop = None
+ compare = None
+ attribute_dict = {}
+ for route_attribute in route_attributes:
+ next_hops = route_attribute["nexthops"]
+ for next_hop in next_hops:
+ next_hop_ip = next_hop["ip"]
+ attribute_dict[next_hop_ip] = route_attribute[attribute]
+
+ # AS_PATH attribute
+ if attribute == "path":
+ # Find next_hop for the route have minimum as_path
+ _next_hop = min(
+ attribute_dict, key=lambda x: len(set(attribute_dict[x]))
+ )
+ compare = "SHORTEST"
- rib_routes_json = run_frr_cmd(rnode, command, isjson=True)
+ # LOCAL_PREF attribute
+ elif attribute == "locPrf":
+ # Find next_hop for the route have highest local preference
+ _next_hop = max(
+ attribute_dict, key=(lambda k: attribute_dict[k])
+ )
+ compare = "HIGHEST"
- # Verifying output dictionary rib_routes_json is not empty
- if not bool(rib_routes_json):
- errormsg = "No route found in RIB of router {}..".format(router)
- return errormsg
+ # WEIGHT attribute
+ elif attribute == "weight":
+ # Find next_hop for the route have highest weight
+ _next_hop = max(
+ attribute_dict, key=(lambda k: attribute_dict[k])
+ )
+ compare = "HIGHEST"
+
+ # ORIGIN attribute
+ elif attribute == "origin":
+ # Find next_hop for the route have IGP as origin, -
+ # - rule is IGP>EGP>INCOMPLETE
+ _next_hop = [
+ key
+ for (key, value) in attribute_dict.iteritems()
+ if value == "IGP"
+ ][0]
+ compare = ""
+
+ # MED attribute
+ elif attribute == "metric":
+ # Find next_hop for the route have LOWEST MED
+ _next_hop = min(
+ attribute_dict, key=(lambda k: attribute_dict[k])
+ )
+ compare = "LOWEST"
- st_found = False
- nh_found = False
- # Find best is installed in RIB
- if route in rib_routes_json:
- st_found = True
- # Verify next_hop in rib_routes_json
- if rib_routes_json[route][0]["nexthops"][0]["ip"] in attribute_dict:
- nh_found = True
- else:
- errormsg = (
- "Incorrect Nexthop for BGP route {} in "
- "RIB of router {}, Expected: {}, Found:"
- " {}\n".format(
+ # Show ip route
+ if addr_type == "ipv4":
+ command_1 = "show ip route"
+ else:
+ command_1 = "show ipv6 route"
+
+ if vrf:
+ cmd = "{} vrf {} json".format(command_1, vrf)
+ else:
+ cmd = "{} json".format(command_1)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if not bool(rib_routes_json):
+ errormsg = "No route found in RIB of router {}..".format(router)
+ return errormsg
+
+ st_found = False
+ nh_found = False
+ # Find best is installed in RIB
+ if route in rib_routes_json:
+ st_found = True
+ # Verify next_hop in rib_routes_json
+ if (
+ rib_routes_json[route][0]["nexthops"][0]["ip"]
+ in attribute_dict
+ ):
+ nh_found = True
+ else:
+ errormsg = (
+ "Incorrect Nexthop for BGP route {} in "
+ "RIB of router {}, Expected: {}, Found:"
+ " {}\n".format(
+ route,
+ router,
+ rib_routes_json[route][0]["nexthops"][0]["ip"],
+ _next_hop,
+ )
+ )
+ return errormsg
+
+ if st_found and nh_found:
+ logger.info(
+ "Best path for prefix: %s with next_hop: %s is "
+ "installed according to %s %s: (%s) in RIB of "
+ "router %s",
route,
- router,
- rib_routes_json[route][0]["nexthops"][0]["ip"],
_next_hop,
+ compare,
+ attribute,
+ attribute_dict[_next_hop],
+ router,
)
- )
- return errormsg
-
- if st_found and nh_found:
- logger.info(
- "Best path for prefix: %s with next_hop: %s is "
- "installed according to %s %s: (%s) in RIB of "
- "router %s",
- route,
- _next_hop,
- compare,
- attribute,
- attribute_dict[_next_hop],
- router,
- )
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1965,7 +2257,7 @@ def verify_best_path_as_per_admin_distance(
return True
-@retry(attempts=10, wait=2, return_is_str=True, initial_wait=2)
+@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None):
"""
This API is to verify whether bgp rib has any
@@ -1995,7 +2287,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
errormsg(str) or True
"""
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ logger.debug("Entering lib API: verify_bgp_rib()")
router_list = tgen.routers()
additional_nexthops_in_required_nhs = []
@@ -2210,7 +2502,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
"routes are: {}\n".format(dut, found_routes)
)
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ logger.debug("Exiting lib API: verify_bgp_rib()")
return True
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 0b19877aff..3de7ab3ebe 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -175,6 +175,49 @@ def run_frr_cmd(rnode, cmd, isjson=False):
raise InvalidCLIError("No actual cmd passed")
+def apply_raw_config(tgen, input_dict):
+
+ """
+ API to configure raw configuration on device. This can be used for any cli
+ which does has not been implemented in JSON.
+
+ Parameters
+ ----------
+ * `tgen`: tgen onject
+ * `input_dict`: configuration that needs to be applied
+
+ Usage
+ -----
+ input_dict = {
+ "r2": {
+ "raw_config": [
+ "router bgp",
+ "no bgp update-group-split-horizon"
+ ]
+ }
+ }
+ Returns
+ -------
+ True or errormsg
+ """
+
+ result = True
+ for router_name in input_dict.keys():
+ config_cmd = input_dict[router_name]["raw_config"]
+
+ if not isinstance(config_cmd, list):
+ config_cmd = [config_cmd]
+
+ frr_cfg_file = "{}/{}/{}".format(TMPDIR, router_name, FRRCFG_FILE)
+ with open(frr_cfg_file, "w") as cfg:
+ for cmd in config_cmd:
+ cfg.write("{}\n".format(cmd))
+
+ result = load_config_to_router(tgen, router_name)
+
+ return result
+
+
def create_common_configuration(
tgen, router, data, config_type=None, build=False, load_config=True
):
@@ -207,6 +250,7 @@ def create_common_configuration(
"bgp_community_list": "! Community List Config\n",
"route_maps": "! Route Maps Config\n",
"bgp": "! BGP Config\n",
+ "vrf": "! VRF Config\n",
}
)
@@ -355,6 +399,7 @@ def reset_config_on_routers(tgen, routerName=None):
"""
Resets configuration on routers to the snapshot created using input JSON
file. It replaces existing router configuration with FRRCFG_BKUP_FILE
+
Parameters
----------
* `tgen` : Topogen object
@@ -370,6 +415,7 @@ def reset_config_on_routers(tgen, routerName=None):
router = router_list[rname]
logger.info("Configuring router %s to initial test configuration", rname)
+
cfg = router.run("vtysh -c 'show running'")
fname = "{}/{}/frr.sav".format(TMPDIR, rname)
dname = "{}/{}/delta.conf".format(TMPDIR, rname)
@@ -387,22 +433,13 @@ def reset_config_on_routers(tgen, routerName=None):
f.write("\n")
f.close()
-
run_cfg_file = "{}/{}/frr.sav".format(TMPDIR, rname)
init_cfg_file = "{}/{}/frr_json_initial.conf".format(TMPDIR, rname)
-
- tempdir = mkdtemp()
- with open(os.path.join(tempdir, "vtysh.conf"), "w") as fd:
- pass
-
- command = "/usr/lib/frr/frr-reload.py --confdir {} --input {} --test {} > {}".format(
- tempdir, run_cfg_file, init_cfg_file, dname
+ command = "/usr/lib/frr/frr-reload.py --input {} --test {} > {}".format(
+ run_cfg_file, init_cfg_file, dname
)
result = call(command, shell=True, stderr=SUB_STDOUT, stdout=SUB_PIPE)
- os.unlink(os.path.join(tempdir, "vtysh.conf"))
- os.rmdir(tempdir)
-
# Assert if command fail
if result > 0:
logger.error("Delta file creation failed. Command executed %s", command)
@@ -459,17 +496,18 @@ def reset_config_on_routers(tgen, routerName=None):
# Router current configuration to log file or console if
# "show_router_config" is defined in "pytest.ini"
if show_router_config:
- logger.info("Configuration on router {} after config reset:".format(rname))
+ logger.info("Configuration on router {} after reset:".format(rname))
logger.info(delta.getvalue())
delta.close()
- logger.debug("Exting API: reset_config_on_routers")
+ logger.debug("Exiting API: reset_config_on_routers")
return True
def load_config_to_router(tgen, routerName, save_bkup=False):
"""
Loads configuration on router from the file FRRCFG_FILE.
+
Parameters
----------
* `tgen` : Topogen object
@@ -481,7 +519,7 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
router_list = tgen.routers()
for rname in ROUTER_LIST:
- if routerName and routerName != rname:
+ if routerName and rname != routerName:
continue
router = router_list[rname]
@@ -504,6 +542,7 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
raise InvalidCLIError("%s" % output)
cfg.truncate(0)
+
except IOError as err:
errormsg = (
"Unable to open config File. error(%s):" " %s",
@@ -514,24 +553,29 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
# Router current configuration to log file or console if
# "show_router_config" is defined in "pytest.ini"
if show_router_config:
+ logger.info("New configuration for router {}:".format(rname))
new_config = router.run("vtysh -c 'show running'")
logger.info(new_config)
- logger.debug("Exting API: load_config_to_router")
+ logger.debug("Exiting API: load_config_to_router")
return True
-def get_frr_ipv6_linklocal(tgen, router, intf=None):
+def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None):
"""
API to get the link local ipv6 address of a perticular interface using
FRR command 'show interface'
+
* `tgen`: tgen onject
* `router` : router for which hightest interface should be
calculated
* `intf` : interface for which linklocal address needs to be taken
+ * `vrf` : VRF name
+
Usage
-----
linklocal = get_frr_ipv6_linklocal(tgen, router, "intf1", RED_A)
+
Returns
-------
1) array of interface names to link local ips.
@@ -544,7 +588,10 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None):
linklocal = []
- cmd = "show interface"
+ if vrf:
+ cmd = "show interface vrf {}".format(vrf)
+ else:
+ cmd = "show interface"
ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd))
@@ -635,6 +682,55 @@ def start_topology(tgen):
tgen.start_router()
+def stop_router(tgen, router):
+ """
+ Router"s current config would be saved to /etc/frr/ for each deamon
+ and router and its deamons would be stopped.
+
+ * `tgen` : topogen object
+ * `router`: Device under test
+ """
+
+ router_list = tgen.routers()
+
+ # Saving router config to /etc/frr, which will be loaded to router
+ # when it starts
+ router_list[router].vtysh_cmd("write memory")
+
+ # Stop router
+ router_list[router].stop()
+
+
+def start_router(tgen, router):
+ """
+ Router will started and config would be loaded from /etc/frr/ for each
+ deamon
+
+ * `tgen` : topogen object
+ * `router`: Device under test
+ """
+
+ logger.debug("Entering lib API: start_router")
+
+ try:
+ router_list = tgen.routers()
+
+ # Router and its deamons would be started and config would
+ # be loaded to router for each deamon from /etc/frr
+ router_list[router].start()
+
+ # Waiting for router to come up
+ sleep(5)
+
+ except Exception as e:
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: start_router()")
+ return True
+
+
def number_to_row(routerName):
"""
Returns the number for the router.
@@ -658,6 +754,190 @@ def number_to_column(routerName):
#############################################
+def create_vrf_cfg(tgen, topo, input_dict=None, build=False):
+ """
+ Create vrf configuration for created topology. VRF
+ configuration is provided in input json file.
+
+ VRF config is done in Linux Kernel:
+ * Create VRF
+ * Attach interface to VRF
+ * Bring up VRF
+
+ 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={
+ "r3": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3",
+ "delete": True
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ]
+ }
+ }
+ result = create_vrf_cfg(tgen, topo, input_dict)
+
+ Returns
+ -------
+ True or False
+ """
+ result = True
+ if not input_dict:
+ input_dict = deepcopy(topo)
+ else:
+ input_dict = deepcopy(input_dict)
+
+ try:
+ for c_router, c_data in input_dict.iteritems():
+ rnode = tgen.routers()[c_router]
+ if "vrfs" in c_data:
+ for vrf in c_data["vrfs"]:
+ config_data = []
+ del_action = vrf.setdefault("delete", False)
+ name = vrf.setdefault("name", None)
+ table_id = vrf.setdefault("id", None)
+ vni = vrf.setdefault("vni", None)
+ del_vni = vrf.setdefault("no_vni", None)
+
+ if del_action:
+ # Kernel cmd- Add VRF and table
+ cmd = "ip link del {} type vrf table {}".format(
+ vrf["name"], vrf["id"]
+ )
+
+ logger.info("[DUT: %s]: Running kernel cmd [%s]", c_router, cmd)
+ rnode.run(cmd)
+
+ # Kernel cmd - Bring down VRF
+ cmd = "ip link set dev {} down".format(name)
+ logger.info("[DUT: %s]: Running kernel cmd [%s]", c_router, cmd)
+ rnode.run(cmd)
+
+ else:
+ if name and table_id:
+ # Kernel cmd- Add VRF and table
+ cmd = "ip link add {} type vrf table {}".format(
+ name, table_id
+ )
+ logger.info(
+ "[DUT: %s]: Running kernel cmd " "[%s]", c_router, cmd
+ )
+ rnode.run(cmd)
+
+ # Kernel cmd - Bring up VRF
+ cmd = "ip link set dev {} up".format(name)
+ logger.info(
+ "[DUT: %s]: Running kernel " "cmd [%s]", c_router, cmd
+ )
+ rnode.run(cmd)
+
+ if "links" in c_data:
+ for destRouterLink, data in sorted(
+ c_data["links"].iteritems()
+ ):
+ # Loopback interfaces
+ if "type" in data and data["type"] == "loopback":
+ interface_name = destRouterLink
+ else:
+ interface_name = data["interface"]
+
+ if "vrf" in data:
+ vrf_list = data["vrf"]
+
+ if type(vrf_list) is not list:
+ vrf_list = [vrf_list]
+
+ for _vrf in vrf_list:
+ cmd = "ip link set {} master {}".format(
+ interface_name, _vrf
+ )
+
+ logger.info(
+ "[DUT: %s]: Running" " kernel cmd [%s]",
+ c_router,
+ cmd,
+ )
+ rnode.run(cmd)
+
+ result = create_common_configuration(
+ tgen, c_router, config_data, "vrf", build=build
+ )
+
+ except InvalidCLIError:
+ # Traceback
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ return result
+
+
+def create_interface_in_kernel(
+ tgen, dut, name, ip_addr, vrf=None, netmask=None, create=True
+):
+ """
+ Cretae interfaces in kernel for ipv4/ipv6
+ Config is done in Linux Kernel:
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `dut` : Device for which interfaces to be added
+ * `name` : interface name
+ * `ip_addr` : ip address for interface
+ * `vrf` : VRF name, to which interface will be associated
+ * `netmask` : netmask value, default is None
+ * `create`: Create interface in kernel, if created then no need
+ to create
+ """
+
+ rnode = tgen.routers()[dut]
+
+ if create:
+ cmd = "sudo ip link add name {} type dummy".format(name)
+ rnode.run(cmd)
+
+ addr_type = validate_ip_address(ip_addr)
+ if addr_type == "ipv4":
+ cmd = "ifconfig {} {} netmask {}".format(name, ip_addr, netmask)
+ else:
+ cmd = "ifconfig {} inet6 add {}/{}".format(name, ip_addr, netmask)
+
+ rnode.run(cmd)
+
+ if vrf:
+ cmd = "ip link set {} master {}".format(name, vrf)
+ rnode.run(cmd)
+
+
def validate_ip_address(ip_address):
"""
Validates the type of ip address
@@ -860,13 +1140,15 @@ def interface_status(tgen, topo, input_dict):
return True
-def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
+def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict=False):
"""
Retries function execution, if return is an errormsg or exception
+
* `attempts`: Number of attempts to make
* `wait`: Number of seconds to wait between each attempt
* `return_is_str`: Return val is an errormsg in case of failure
* `initial_wait`: Sleeps for this much seconds before executing function
+
"""
def _retry(func):
@@ -883,15 +1165,20 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
sleep(initial_wait)
_return_is_str = kwargs.pop("return_is_str", return_is_str)
+ _return_is_dict = kwargs.pop("return_is_str", return_is_dict)
for i in range(1, _attempts + 1):
try:
_expected = kwargs.setdefault("expected", True)
kwargs.pop("expected")
ret = func(*args, **kwargs)
logger.debug("Function returned %s" % ret)
- if return_is_str and isinstance(ret, bool) and _expected:
+ if _return_is_str and isinstance(ret, bool) and _expected:
return ret
- if isinstance(ret, str) and _expected is False:
+ if (
+ isinstance(ret, str) or isinstance(ret, unicode)
+ ) and _expected is False:
+ return ret
+ if _return_is_dict and isinstance(ret, dict):
return ret
if _attempts == i:
@@ -945,16 +1232,19 @@ def create_interfaces_cfg(tgen, topo, build=False):
"""
Create interface configuration for created topology. Basic Interface
configuration is provided in input json file.
+
Parameters
----------
* `tgen` : Topogen object
* `topo` : json file data
* `build` : Only for initial setup phase this is set as True.
+
Returns
-------
True or False
"""
result = False
+ topo = deepcopy(topo)
try:
for c_router, c_data in topo.iteritems():
@@ -965,13 +1255,30 @@ def create_interfaces_cfg(tgen, topo, build=False):
interface_name = destRouterLink
else:
interface_name = data["interface"]
+
interface_data.append("interface {}".format(str(interface_name)))
if "ipv4" in data:
intf_addr = c_data["links"][destRouterLink]["ipv4"]
- interface_data.append("ip address {}".format(intf_addr))
+
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ip address {}".format(intf_addr))
+ else:
+ interface_data.append("ip address {}".format(intf_addr))
if "ipv6" in data:
intf_addr = c_data["links"][destRouterLink]["ipv6"]
- interface_data.append("ipv6 address {}".format(intf_addr))
+
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ipv6 address {}".format(intf_addr))
+ else:
+ interface_data.append("ipv6 address {}".format(intf_addr))
+
+ if "ipv6-link-local" in data:
+ intf_addr = c_data["links"][destRouterLink]["ipv6-link-local"]
+
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ipv6 address {}".format(intf_addr))
+ else:
+ interface_data.append("ipv6 address {}\n".format(intf_addr))
result = create_common_configuration(
tgen, c_router, interface_data, "interface_config", build=build
@@ -988,11 +1295,13 @@ def create_interfaces_cfg(tgen, topo, build=False):
def create_static_routes(tgen, input_dict, build=False):
"""
Create static routes for given router as defined in input_dict
+
Parameters
----------
* `tgen` : Topogen object
* `input_dict` : Input dict data, required when configuring from testcase
* `build` : Only for initial setup phase this is set as True.
+
Usage
-----
input_dict should be in the format below:
@@ -1002,7 +1311,9 @@ def create_static_routes(tgen, input_dict, build=False):
# admin_distance: admin distance for route/routes.
# next_hop: starting next-hop address
# tag: tag id for static routes
+ # vrf: VRF name in which static routes needs to be created
# delete: True if config to be removed. Default False.
+
Example:
"routers": {
"r1": {
@@ -1012,24 +1323,27 @@ def create_static_routes(tgen, input_dict, build=False):
"no_of_ip": 9,
"admin_distance": 100,
"next_hop": "10.0.0.1",
- "tag": 4001
+ "tag": 4001,
+ "vrf": "RED_A"
"delete": true
}
]
}
}
+
Returns
-------
errormsg(str) or True
"""
result = False
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ logger.debug("Entering lib API: create_static_routes()")
input_dict = deepcopy(input_dict)
+
try:
for router in input_dict.keys():
if "static_routes" not in input_dict[router]:
errormsg = "static_routes not present in input_dict"
- logger.debug(errormsg)
+ logger.info(errormsg)
continue
static_routes_list = []
@@ -1037,27 +1351,38 @@ def create_static_routes(tgen, input_dict, build=False):
static_routes = input_dict[router]["static_routes"]
for static_route in static_routes:
del_action = static_route.setdefault("delete", False)
- # No of IPs
no_of_ip = static_route.setdefault("no_of_ip", 1)
- admin_distance = static_route.setdefault("admin_distance", None)
- tag = static_route.setdefault("tag", None)
- if "next_hop" not in static_route or "network" not in static_route:
- errormsg = "'next_hop' or 'network' missing in" " input_dict"
- return errormsg
-
- next_hop = static_route["next_hop"]
- network = static_route["network"]
+ network = static_route.setdefault("network", [])
if type(network) is not list:
network = [network]
+ admin_distance = static_route.setdefault("admin_distance", None)
+ tag = static_route.setdefault("tag", None)
+ vrf = static_route.setdefault("vrf", None)
+ interface = static_route.setdefault("interface", None)
+ next_hop = static_route.setdefault("next_hop", None)
+ nexthop_vrf = static_route.setdefault("nexthop_vrf", None)
+
ip_list = generate_ips(network, no_of_ip)
for ip in ip_list:
addr_type = validate_ip_address(ip)
if addr_type == "ipv4":
- cmd = "ip route {} {}".format(ip, next_hop)
+ cmd = "ip route {}".format(ip)
else:
- cmd = "ipv6 route {} {}".format(ip, next_hop)
+ cmd = "ipv6 route {}".format(ip)
+
+ if interface:
+ cmd = "{} {}".format(cmd, interface)
+
+ if next_hop:
+ cmd = "{} {}".format(cmd, next_hop)
+
+ if nexthop_vrf:
+ cmd = "{} nexthop-vrf {}".format(cmd, nexthop_vrf)
+
+ if vrf:
+ cmd = "{} vrf {}".format(cmd, vrf)
if tag:
cmd = "{} tag {}".format(cmd, str(tag))
@@ -1080,7 +1405,7 @@ def create_static_routes(tgen, input_dict, build=False):
logger.error(errormsg)
return errormsg
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ logger.debug("Exiting lib API: create_static_routes()")
return result
@@ -1433,6 +1758,9 @@ def create_route_maps(tgen, input_dict, build=False):
"large_community_list", {}
)
+ metric = match_data.setdefault("metric", None)
+ source_vrf = match_data.setdefault("source-vrf", None)
+
if ipv4_data:
# fetch prefix list data from rmap
prefix_name = ipv4_data.setdefault("prefix_lists", None)
@@ -1525,6 +1853,14 @@ def create_route_maps(tgen, input_dict, build=False):
cmd = "{} exact-match".format(cmd)
rmap_data.append(cmd)
+ if source_vrf:
+ cmd = "match source-vrf {}".format(source_vrf)
+ rmap_data.append(cmd)
+
+ if metric:
+ cmd = "match metric {}".format(metric)
+ rmap_data.append(cmd)
+
result = create_common_configuration(
tgen, router, rmap_data, "route_maps", build=build
)
@@ -1689,17 +2025,97 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
interface_set_status(router_list[dut], intf_name, ifaceaction)
+def addKernelRoute(
+ tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None
+):
+ """
+ Add route to kernel
+
+ Parameters:
+ -----------
+ * `tgen` : Topogen object
+ * `router`: router for which kernal routes needs to be added
+ * `intf`: interface name, for which kernal routes needs to be added
+ * `bindToAddress`: bind to <host>, an interface or multicast
+ address
+
+ returns:
+ --------
+ errormsg or True
+ """
+
+ logger.debug("Entering lib API: addKernelRoute()")
+
+ rnode = tgen.routers()[router]
+
+ if type(group_addr_range) is not list:
+ group_addr_range = [group_addr_range]
+
+ for grp_addr in group_addr_range:
+
+ addr_type = validate_ip_address(grp_addr)
+ if addr_type == "ipv4":
+ if next_hop is not None:
+ cmd = "ip route add {} via {}".format(grp_addr, next_hop)
+ else:
+ cmd = "ip route add {} dev {}".format(grp_addr, intf)
+ if del_action:
+ cmd = "ip route del {}".format(grp_addr)
+ verify_cmd = "ip route"
+ elif addr_type == "ipv6":
+ if intf and src:
+ cmd = "ip -6 route add {} dev {} src {}".format(grp_addr, intf, src)
+ else:
+ cmd = "ip -6 route add {} via {}".format(grp_addr, next_hop)
+ verify_cmd = "ip -6 route"
+ if del_action:
+ cmd = "ip -6 route del {}".format(grp_addr)
+
+ logger.info("[DUT: {}]: Running command: [{}]".format(router, cmd))
+ output = rnode.run(cmd)
+
+ # Verifying if ip route added to kernal
+ result = rnode.run(verify_cmd)
+ logger.debug("{}\n{}".format(verify_cmd, result))
+ if "/" in grp_addr:
+ ip, mask = grp_addr.split("/")
+ if mask == "32" or mask == "128":
+ grp_addr = ip
+
+ if not re_search(r"{}".format(grp_addr), result) and mask is not "0":
+ errormsg = (
+ "[DUT: {}]: Kernal route is not added for group"
+ " address {} Config output: {}".format(router, grp_addr, output)
+ )
+
+ return errormsg
+
+ logger.debug("Exiting lib API: addKernelRoute()")
+ return True
+
+
#############################################
# Verification APIs
#############################################
-@retry(attempts=10, return_is_str=True, initial_wait=2)
-def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
+@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+def verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict,
+ next_hop=None,
+ protocol=None,
+ tag=None,
+ metric=None,
+ fib=None,
+):
"""
Data will be read from input_dict or input JSON file, API will generate
same prefixes, which were redistributed by either create_static_routes() or
advertise_networks_using_network_command() and do will verify next_hop and
each prefix/routes is present in "show ip/ipv6 route {bgp/stataic} json"
command o/p.
+
Parameters
----------
* `tgen` : topogen object
@@ -1709,12 +2125,14 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
* `next_hop`[optional]: next_hop which needs to be verified,
default: static
* `protocol`[optional]: protocol, default = None
+
Usage
-----
# RIB can be verified for static routes OR network advertised using
network command. Following are input_dicts to create static routes
and advertise networks using network command. Any one of the input_dict
can be passed to verify_rib() to verify routes in DUT"s RIB.
+
# Creating static routes for r1
input_dict = {
"r1": {
@@ -1732,186 +2150,328 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
dut = "r2"
protocol = "bgp"
result = verify_rib(tgen, "ipv4", dut, input_dict, protocol = protocol)
+
Returns
-------
errormsg(str) or True
"""
- logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ logger.info("Entering lib API: verify_rib()")
router_list = tgen.routers()
+ additional_nexthops_in_required_nhs = []
+ found_hops = []
for routerInput in input_dict.keys():
for router, rnode in router_list.iteritems():
if router != dut:
continue
+ logger.info("Checking router %s RIB:", router)
+
# Verifying RIB routes
if addr_type == "ipv4":
- if protocol:
- command = "show ip route {} json".format(protocol)
- else:
- command = "show ip route json"
+ command = "show ip route"
else:
- if protocol:
- command = "show ipv6 route {} json".format(protocol)
- else:
- command = "show ipv6 route json"
-
- logger.info("Checking router %s RIB:", router)
- rib_routes_json = run_frr_cmd(rnode, command, isjson=True)
+ command = "show ipv6 route"
- # Verifying output dictionary rib_routes_json is not empty
- if bool(rib_routes_json) is False:
- errormsg = "No {} route found in rib of router {}..".format(
- protocol, router
- )
- return errormsg
+ found_routes = []
+ missing_routes = []
if "static_routes" in input_dict[routerInput]:
static_routes = input_dict[routerInput]["static_routes"]
- st_found = False
- nh_found = False
- found_routes = []
- missing_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)
+
+ if protocol:
+ cmd = "{} {}".format(cmd, protocol)
+
+ cmd = "{} json".format(cmd)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if bool(rib_routes_json) is False:
+ errormsg = "No route found in rib of router {}..".format(router)
+ return errormsg
+
network = static_route["network"]
if "no_of_ip" in static_route:
no_of_ip = static_route["no_of_ip"]
else:
no_of_ip = 1
+ if "tag" in static_route:
+ _tag = static_route["tag"]
+ else:
+ _tag = None
+
# Generating IPs for verification
ip_list = generate_ips(network, no_of_ip)
+ st_found = False
+ nh_found = False
+
for st_rt in ip_list:
st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
+ _addr_type = validate_ip_address(st_rt)
+ if _addr_type != addr_type:
+ continue
+
if st_rt in rib_routes_json:
st_found = True
found_routes.append(st_rt)
- if next_hop:
+ if fib and next_hop:
if type(next_hop) is not list:
next_hop = [next_hop]
+ for mnh in range(0, len(rib_routes_json[st_rt])):
+ if (
+ "fib"
+ in rib_routes_json[st_rt][mnh]["nexthops"][0]
+ ):
+ found_hops.append(
+ [
+ rib_r["ip"]
+ for rib_r in rib_routes_json[st_rt][
+ mnh
+ ]["nexthops"]
+ ]
+ )
+
+ if found_hops[0]:
+ missing_list_of_nexthops = set(
+ found_hops[0]
+ ).difference(next_hop)
+ additional_nexthops_in_required_nhs = set(
+ next_hop
+ ).difference(found_hops[0])
+
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Nexthop "
+ "%s is not active for route %s in "
+ "RIB of router %s\n",
+ additional_nexthops_in_required_nhs,
+ st_rt,
+ dut,
+ )
+ errormsg = (
+ "Nexthop {} is not active"
+ " for route {} in RIB of router"
+ " {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt,
+ dut,
+ )
+ )
+ return errormsg
+ else:
+ nh_found = True
+
+ elif next_hop and fib is None:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
found_hops = [
rib_r["ip"]
for rib_r in rib_routes_json[st_rt][0]["nexthops"]
]
- for nh in found_hops:
- nh_found = False
- if nh and nh in next_hop:
- nh_found = True
- else:
+
+ if found_hops:
+ missing_list_of_nexthops = set(
+ found_hops
+ ).difference(next_hop)
+ additional_nexthops_in_required_nhs = set(
+ next_hop
+ ).difference(found_hops)
+
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Missing nexthop %s for route"
+ " %s in RIB of router %s\n",
+ additional_nexthops_in_required_nhs,
+ st_rt,
+ dut,
+ )
errormsg = (
- "Nexthop {} is Missing for {}"
- " route {} in RIB of router"
- " {}\n".format(
- next_hop, protocol, st_rt, dut
+ "Nexthop {} is Missing for "
+ "route {} in RIB of router {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt,
+ dut,
)
)
-
return errormsg
+ else:
+ nh_found = True
+
+ if tag:
+ if "tag" not in rib_routes_json[st_rt][0]:
+ errormsg = (
+ "[DUT: {}]: tag is not"
+ " present for"
+ " route {} in RIB \n".format(dut, st_rt)
+ )
+ return errormsg
+
+ if _tag != rib_routes_json[st_rt][0]["tag"]:
+ errormsg = (
+ "[DUT: {}]: tag value {}"
+ " is not matched for"
+ " route {} in RIB \n".format(dut, _tag, st_rt,)
+ )
+ return errormsg
+
+ if metric is not None:
+ if "metric" not in rib_routes_json[st_rt][0]:
+ errormsg = (
+ "[DUT: {}]: metric is"
+ " not present for"
+ " route {} in RIB \n".format(dut, st_rt)
+ )
+ return errormsg
+
+ if metric != rib_routes_json[st_rt][0]["metric"]:
+ errormsg = (
+ "[DUT: {}]: metric value "
+ "{} is not matched for "
+ "route {} in RIB \n".format(dut, metric, st_rt,)
+ )
+ return errormsg
+
else:
missing_routes.append(st_rt)
if nh_found:
logger.info(
- "Found next_hop %s for all routes in RIB of" " router %s\n",
- next_hop,
- dut,
+ "[DUT: {}]: Found next_hop {} for all bgp"
+ " routes in RIB".format(router, next_hop)
)
- if not st_found and len(missing_routes) > 0:
- errormsg = (
- "Missing route in RIB of router {}, routes: "
- "{}\n".format(dut, missing_routes)
+ if len(missing_routes) > 0:
+ errormsg = "[DUT: {}]: Missing route in RIB, " "routes: {}".format(
+ dut, missing_routes
)
return errormsg
- logger.info(
- "Verified routes in router %s RIB, found routes" " are: %s\n",
- dut,
- found_routes,
- )
+ if found_routes:
+ logger.info(
+ "[DUT: %s]: Verified routes in RIB, found" " routes are: %s\n",
+ dut,
+ found_routes,
+ )
continue
if "bgp" in input_dict[routerInput]:
if (
"advertise_networks"
- in input_dict[routerInput]["bgp"]["address_family"][addr_type][
+ not in input_dict[routerInput]["bgp"]["address_family"][addr_type][
"unicast"
]
):
+ continue
- found_routes = []
- missing_routes = []
- advertise_network = input_dict[routerInput]["bgp"][
- "address_family"
- ][addr_type]["unicast"]["advertise_networks"]
+ found_routes = []
+ missing_routes = []
+ advertise_network = input_dict[routerInput]["bgp"]["address_family"][
+ addr_type
+ ]["unicast"]["advertise_networks"]
- for advertise_network_dict in advertise_network:
- start_ip = advertise_network_dict["network"]
- if "no_of_network" in advertise_network_dict:
- no_of_network = advertise_network_dict["no_of_network"]
- else:
- no_of_network = 1
-
- # Generating IPs for verification
- ip_list = generate_ips(start_ip, no_of_network)
- for st_rt in ip_list:
- st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
-
- found = False
- nh_found = False
- if st_rt in rib_routes_json:
- found = True
- found_routes.append(st_rt)
-
- if next_hop:
- if type(next_hop) is not list:
- next_hop = [next_hop]
-
- for nh in next_hop:
- for nh_json in rib_routes_json[st_rt][0][
- "nexthops"
- ]:
- if nh != nh_json["ip"]:
- continue
- nh_found = True
-
- if not nh_found:
- errormsg = (
- "Nexthop {} is Missing"
- " for {} route {} in "
- "RIB of router {}\n".format(
- next_hop, protocol, st_rt, dut
- )
- )
- return errormsg
+ # Continue if there are no network advertise
+ if len(advertise_network) == 0:
+ continue
+
+ for advertise_network_dict in advertise_network:
+ if "vrf" in advertise_network_dict:
+ cmd = "{} vrf {} json".format(command, static_route["vrf"])
+ else:
+ cmd = "{} json".format(command)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if bool(rib_routes_json) is False:
+ errormsg = "No route found in rib of router {}..".format(router)
+ return errormsg
+
+ start_ip = advertise_network_dict["network"]
+ if "no_of_network" in advertise_network_dict:
+ no_of_network = advertise_network_dict["no_of_network"]
+ else:
+ no_of_network = 1
+
+ # Generating IPs for verification
+ ip_list = generate_ips(start_ip, no_of_network)
+ st_found = False
+ nh_found = False
+
+ for st_rt in ip_list:
+ st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
+
+ _addr_type = validate_ip_address(st_rt)
+ if _addr_type != addr_type:
+ continue
+
+ if st_rt in rib_routes_json:
+ st_found = True
+ found_routes.append(st_rt)
+
+ if next_hop:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
+
+ count = 0
+ for nh in next_hop:
+ for nh_dict in rib_routes_json[st_rt][0]["nexthops"]:
+ if nh_dict["ip"] != nh:
+ continue
+ else:
+ count += 1
+ if count == len(next_hop):
+ nh_found = True
else:
- missing_routes.append(st_rt)
+ errormsg = (
+ "Nexthop {} is Missing"
+ " for route {} in "
+ "RIB of router {}\n".format(next_hop, st_rt, dut)
+ )
+ return errormsg
+ else:
+ missing_routes.append(st_rt)
- if nh_found:
- logger.info(
- "Found next_hop {} for all routes in RIB"
- " of router {}\n".format(next_hop, dut)
- )
+ if nh_found:
+ logger.info(
+ "Found next_hop {} for all routes in RIB"
+ " of router {}\n".format(next_hop, dut)
+ )
- if not found and len(missing_routes) > 0:
- errormsg = (
- "Missing {} route in RIB of router {}, "
- "routes: {} \n".format(addr_type, dut, missing_routes)
- )
- return errormsg
+ if len(missing_routes) > 0:
+ errormsg = (
+ "Missing {} route in RIB of router {}, "
+ "routes: {} \n".format(addr_type, dut, missing_routes)
+ )
+ return errormsg
+ if found_routes:
logger.info(
"Verified {} routes in router {} RIB, found"
" routes are: {}\n".format(addr_type, dut, found_routes)
)
- logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ logger.info("Exiting lib API: verify_rib()")
return True
diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py
index b25317ba7f..24b61981d6 100644
--- a/tests/topotests/lib/topojson.py
+++ b/tests/topotests/lib/topojson.py
@@ -37,6 +37,7 @@ from lib.common_config import (
create_prefix_lists,
create_route_maps,
create_bgp_community_lists,
+ create_vrf_cfg,
)
from lib.bgp import create_router_bgp
@@ -49,7 +50,6 @@ def build_topo_from_json(tgen, topo):
Reads configuration from JSON file. Adds routers, creates interface
names dynamically and link routers as defined in JSON to create
topology. Assigns IPs dynamically to all interfaces of each router.
-
* `tgen`: Topogen object
* `topo`: json file data
"""
@@ -203,6 +203,7 @@ def build_config_from_json(tgen, topo, save_bkup=True):
func_dict = OrderedDict(
[
+ ("vrfs", create_vrf_cfg),
("links", create_interfaces_cfg),
("static_routes", create_static_routes),
("prefix_lists", create_prefix_lists),