summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json563
-rw-r--r--tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json563
-rwxr-xr-xtests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py1848
-rwxr-xr-xtests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py962
-rw-r--r--tests/topotests/lib/bgp.py11
-rw-r--r--tests/topotests/lib/common_config.py298
6 files changed, 4226 insertions, 19 deletions
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json
new file mode 100644
index 0000000000..b1d7d09db8
--- /dev/null
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo1.json
@@ -0,0 +1,563 @@
+{
+ "address_types": ["ipv4","ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "vrfs":[
+ {
+ "name": "ISR",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["11.11.11.1/32", "11.11.11.11/32"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["11:11::1/128", "11:11::11/128"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["10.10.10.10/32", "10.10.10.100/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["10:10::10/128", "10:10::100/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r2": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "vrfs":[
+ {
+ "name": "ISR",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["22.22.22.2/32", "22.22.22.22/32"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["22:22::2/128", "22:22::22/128"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["20.20.20.20/32", "20.20.20.200/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["20:20::20/128", "20:20::200/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r3": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":
+ [
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["30.30.30.3/32", "30.30.30.30/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["30:30::3/128", "30:30::30/128"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50.50.50.5/32", "50.50.50.50/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50:50::5/128", "50:50::50/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r4": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["40.40.40.4/32", "40.40.40.40/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["40:40::4/128", "40:40::40/128"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50.50.50.5/32", "50.50.50.50/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50:50::5/128", "50:50::50/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json
new file mode 100644
index 0000000000..b1d7d09db8
--- /dev/null
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/bgp_vrf_dynamic_route_leak_topo2.json
@@ -0,0 +1,563 @@
+{
+ "address_types": ["ipv4","ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 30,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:db8:f::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "vrfs":[
+ {
+ "name": "ISR",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["11.11.11.1/32", "11.11.11.11/32"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["11:11::1/128", "11:11::11/128"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["10.10.10.10/32", "10.10.10.100/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["10:10::10/128", "10:10::100/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r2": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "vrfs":[
+ {
+ "name": "ISR",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "next_hop_self": true,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["22.22.22.2/32", "22.22.22.22/32"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["22:22::2/128", "22:22::22/128"],
+ "next_hop":"Null0",
+ "vrf": "ISR"
+ },
+ {
+ "network": ["20.20.20.20/32", "20.20.20.200/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["20:20::20/128", "20:20::200/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r3": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":
+ [
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["30.30.30.3/32", "30.30.30.30/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["30:30::3/128", "30:30::30/128"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50.50.50.5/32", "50.50.50.50/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50:50::5/128", "50:50::50/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r4": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "keepalivetimer": 1,
+ "holddowntimer": 3,
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network": ["40.40.40.4/32", "40.40.40.40/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["40:40::4/128", "40:40::40/128"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50.50.50.5/32", "50.50.50.50/32"],
+ "next_hop":"Null0"
+ },
+ {
+ "network": ["50:50::5/128", "50:50::50/128"],
+ "next_hop":"Null0"
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py
new file mode 100755
index 0000000000..1947548b3e
--- /dev/null
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo1.py
@@ -0,0 +1,1848 @@
+#!/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 Dynamic Route Leaking:
+
+1. Verify that dynamically imported routes are further advertised
+ to iBGP peers(peer in cluster).
+2. Verify matching a prefix based on community attribute and
+ importing it by stripping off this value
+3. Verify the route-map operation along with dynamic import command.
+4. Verifying the JSON outputs for all supported commands
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import platform
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+sys.path.append(os.path.join(CWD, '../lib/'))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+from mininet.topo import Topo
+
+from lib.common_config import (
+ start_topology, write_test_header, check_address_types,
+ write_test_footer, reset_config_on_routers,
+ verify_rib, step, create_route_maps,
+ shutdown_bringup_interface, create_static_routes,
+ create_prefix_lists, create_bgp_community_lists,
+ create_interface_in_kernel,
+ check_router_status, verify_cli_json,
+ get_frr_ipv6_linklocal, verify_fib_routes
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence, create_router_bgp,
+ clear_bgp, verify_bgp_community, verify_bgp_rib
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/bgp_vrf_dynamic_route_leak_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": "11.11.11.1/32", "ipv6": "11:11::1/128"}
+NETWORK1_2 = {"ipv4": "11.11.11.11/32", "ipv6": "11:11::11/128"}
+NETWORK1_3 = {"ipv4": "10.10.10.10/32", "ipv6": "10:10::10/128"}
+NETWORK1_4 = {"ipv4": "10.10.10.100/32", "ipv6": "10:10::100/128"}
+
+NETWORK2_1 = {"ipv4": "22.22.22.2/32", "ipv6": "22:22::2/128"}
+NETWORK2_2 = {"ipv4": "22.22.22.22/32", "ipv6": "22:22::22/128"}
+NETWORK2_3 = {"ipv4": "20.20.20.20/32", "ipv6": "20:20::20/128"}
+NETWORK2_4 = {"ipv4": "20.20.20.200/32", "ipv6": "20:20::200/128"}
+
+NETWORK3_1 = {"ipv4": "30.30.30.3/32", "ipv6": "30:30::3/128"}
+NETWORK3_2 = {"ipv4": "30.30.30.30/32", "ipv6": "30:30::30/128"}
+NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
+NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
+
+NETWORK4_1 = {"ipv4": "40.40.40.4/32", "ipv6": "40:40::4/128"}
+NETWORK4_2 = {"ipv4": "40.40.40.40/32", "ipv6": "40:40::40/128"}
+NETWORK4_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
+NETWORK4_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
+
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+LOOPBACK_1 = {"ipv4": "10.0.0.7/24", "ipv6": "fd00:0:0:1::7/64",
+ "ipv4_mask": "255.255.255.0", "ipv6_mask": None}
+LOOPBACK_2 = {"ipv4": "10.0.0.16/24", "ipv6": "fd00:0:0:3::5/64",
+ "ipv4_mask": "255.255.255.0", "ipv6_mask": None}
+PREFERRED_NEXT_HOP = "global"
+
+
+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
+ """
+
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Run these tests for kernel version 4.19 or above
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('BGP vrf dynamic route leak tests will not run '
+ '(have kernel "{}", but it requires >= 4.19)'.\
+ format(platform.release()))
+ pytest.skip(error_msg)
+
+ # 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)
+
+#####################################################
+#
+# Local APIs
+#
+#####################################################
+
+def disable_route_map_to_prefer_global_next_hop(tgen, topo):
+ """
+ This API is to remove prefer global route-map applied on neighbors
+
+ Parameter:
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : Input JSON data
+
+ Returns:
+ --------
+ True/errormsg
+
+ """
+
+ logger.info("Remove prefer-global rmap applied on neighbors")
+ input_dict = {
+ "r1": {
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r2": {
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "ISR",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "bgp":
+ [
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r4": {
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ return True
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+def test_dynamic_imported_routes_advertised_to_iBGP_peer_p0(request):
+ """
+ TC5_FUNC_5:
+ 1.5.5. Verify that dynamically imported routes are further advertised
+ to iBGP peers(peer in cluster).
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Redistribute configured static routes into BGP process"
+ " on R1 and R3/R4")
+
+ input_dict_1={}
+ DUT = ["r1", "r3", "r4"]
+ VRFS = ["default", "default", "default"]
+ AS_NUM = [100, 300, 400]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that R1 receives BGP routes from R3 and R4 in "
+ "vrf default.")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_1[addr_type], \
+ NETWORK3_2[addr_type], \
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ input_routes_r4 = {
+ "r4": {
+ "static_routes": [{
+ "network": [
+ NETWORK4_1[addr_type], \
+ NETWORK4_2[addr_type], \
+ NETWORK4_3[addr_type], \
+ NETWORK4_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ DUT = ["r1", "r2"]
+ INPUT_DICT = [input_routes_r3, input_routes_r4]
+
+ for dut, routes in zip(DUT, INPUT_DICT):
+ result = verify_bgp_rib(tgen, addr_type, dut, routes)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ result = verify_fib_routes(tgen, addr_type, dut, routes)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Import from default vrf into vrf ISR on R1")
+
+ input_dict_isr={}
+ DUT = ["r1", "r2"]
+ VRFS = ["ISR", "ISR"]
+ AS_NUM = [100, 100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "default"
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that default vrf's imported routes are installed "
+ "in RIB/FIB of vrf ISR on R1:")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_1[addr_type], \
+ NETWORK3_2[addr_type], \
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ],
+ "vrf": "ISR"
+ }]
+ }
+ }
+
+ input_routes_r4 = {
+ "r4": {
+ "static_routes": [{
+ "network": [
+ NETWORK4_1[addr_type], \
+ NETWORK4_2[addr_type], \
+ NETWORK4_3[addr_type], \
+ NETWORK4_4[addr_type]
+ ],
+ "vrf": "ISR"
+ }]
+ }
+ }
+
+ INPUT_DICT_VRF = [input_routes_r3, input_routes_r4]
+
+ for routes in INPUT_DICT_VRF:
+ result = verify_bgp_rib(tgen, addr_type, "r1", routes)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ result = verify_fib_routes(tgen, addr_type, "r1", routes)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ intf_r2_r1 = topo["routers"]["r2"]["links"]["r1-link1"]
+ for addr_type in ADDR_TYPES:
+
+ step("Create a loopback10 interface on R1 with below IP address and "
+ "associate with vrf ISR:")
+
+ create_interface_in_kernel(tgen, "r1", "loopback2",
+ LOOPBACK_2[addr_type],
+ "ISR",
+ LOOPBACK_2["{}_mask".\
+ format(addr_type)])
+
+ for addr_type in ADDR_TYPES:
+
+ step("On router R1 Change the next-hop of static routes in vrf "
+ "ISR to LOOPBACK_1")
+
+ input_routes_r1= {
+ "r1": {
+ "static_routes":[
+ {
+ "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]],
+ "next_hop":"Null0",
+ "delete": True
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_routes_r1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_routes_r1= {
+ "r1": {
+ "static_routes":[
+ {
+ "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]],
+ "next_hop": (intf_r2_r1[addr_type]).split("/")[0]
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_routes_r1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that, though R1 originating BGP routes with next-hop"
+ " 24.1.1.2/24::1:2, which is local to R2(but in default vrf)"
+ ", R2 must receives and install all routes from R1 in vrf ISR.")
+ step("Verify on R2, that it now rejects 10.10.10.x routes originated "
+ "from R1. As next-hop IP is local to R2's vrf ISR.")
+
+ input_routes_r1= {
+ "r1": {
+ "static_routes":[
+ {
+ "network": [NETWORK1_3[addr_type], NETWORK1_4[addr_type]],
+ "vrf": "ISR"
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Routes are still present \n Error {}". \
+ format(tc_name, result))
+
+ write_test_footer(tc_name)
+
+
+def test_dynamic_imported_matching_prefix_based_on_community_list_p0(request):
+ """
+ TC7_FUNC_7:
+ 1.5.7. Verify matching a prefix based on community attribute and
+ importing it by stripping off this value
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure route-map to set community attribute for a specific"
+ "prefix on R1 in vrf ISR")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_ABC_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100"
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_XYZ_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pflist_ABC_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "community": {"num": "100:100"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply this route-map on R1 to vrf ISR while redistributing the"
+ " prefixes into BGP")
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ }
+ }
+ ]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure another route-map for filtering the prefixes based on"
+ " community attribute while importing into default vrf")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "none"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply the route-map while Importing vrf ISR's prefixes into "
+ "default vrf on router R1:")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify on R1 that only prefixes with community value 100:100"
+ "in vrf ISR are imported to vrf default. While importing, the"
+ " community value has been stripped off:")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ input_dict_comm = {
+ "community": "100:100"
+ }
+
+ result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]],
+ input_dict_comm, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error: Commnunity is not stipped off, {}".format(
+ tc_name, result))
+
+ for addr_type in ADDR_TYPES:
+
+ step("Remove/re-add route-map XYZ from redistribution.")
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ },
+ "delete": True
+ }]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that all the routes disappear from vrf default when "
+ "route-map is removed from redistribution, and appear again "
+ "when route-map is re-added to redistribution in vrf ISR.")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ for addr_type in ADDR_TYPES:
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ }
+ }]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Remove/re-add route-map IMP form import statement.")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type),
+ "delete": True
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that when route-map IMP is removed all the prefixes of"
+ " vrf ISR are imported to vrf default. However when route-map "
+ "IMP is re-added only 11.11.11.1 and 11:11::1 (with community "
+ "value) are imported.")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Delete/Re-add prefix-list ABC.")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_ABC_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit",
+ "delete": True
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ input_dict_pf["r1"]["prefix_lists"][addr_type]["pflist_ABC_{}".\
+ format(addr_type)][0]["delete"]=False
+
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ step("Delete/Re-add community-list COMM.")
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100",
+ "delete": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ input_dict_cl["r1"]["bgp_community_lists"][0]["delete"]=False
+
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ step("Delete/Re-add route-map XYZ.")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_XYZ_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pflist_ABC_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "community": {"num": "100:100"}
+ },
+ "delete": True
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ input_dict_rm["r1"]["route_maps"]["rmap_XYZ_{}".format(addr_type)][0]["delete"]=False
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ step("Delete/Re-add route-map IMP.")
+
+ input_dict_rm2 = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "none"}
+ },
+ "delete": True
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ input_dict_rm2["r1"]["route_maps"]["rmap_IMP_{}".format(addr_type)][0]["delete"]=False
+
+ result = create_route_maps(tgen, input_dict_rm2)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_routemap_operatons_with_dynamic_import_p0(request):
+ """
+ TC8_FUNC_8:
+ 1.5.8. Verify the route-map operation along with dynamic import command.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure route-map to set community attribute for a specific"
+ "prefix on R1 in vrf ISR")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_ABC_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100"
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_XYZ_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pflist_ABC_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "community": {"num": "100:100"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply this route-map on R1 to vrf ISR while redistributing the"
+ " prefixes into BGP")
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ }
+ }
+ ]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure another route-map for filtering the prefixes based on"
+ " community attribute while importing into default vrf")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "500:500"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply the route-map while Importing vrf ISR's prefixes into "
+ "default vrf on router R1:")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify on R1 that only prefixes with community value 100:100"
+ "in vrf ISR are imported to vrf default. While importing, the"
+ " community value has been stripped off:")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Applying route-map first followed by import VRF command.")
+ step("Apply the route-map while Importing vrf ISR's prefixes into "
+ "default vrf on router R1:")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR",
+ "delete": True
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that until 'import VRF command' is not configured, "
+ "routes are not imported. After configuring 'import VRF command'"
+ " repeat step-4 for verification")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still present \n {}".\
+ format(tc_name, result))
+
+ for addr_type in ADDR_TYPES:
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Delete/re-add import vrf ISR command multiple times in default"
+ "vrf.")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR",
+ "delete": True
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ step("Verify that when import vrf ISR command is deleted, "
+ "all routes of vrf ISR disappear from default vrf and "
+ "when it's re-configured, repeat step-4 for verification.")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Routes are still present, Error {}". \
+ format(tc_name, result))
+
+ input_dict_isr["r1"]["bgp"][0]["address_family"][addr_type]["unicast"][
+ "import"]["delete"]=False
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result))
+
+ for addr_type in ADDR_TYPES:
+
+ step("Delete and re-configure route-map IMP from global config when "
+ "import and route-maps are applied in a ISR vrf.")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "500:500"}
+ },
+ "delete": True
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Routes are still present, Error {}". \
+ format(tc_name, result))
+
+ input_dict_rm["r1"]["route_maps"]["rmap_IMP_{}".\
+ format(addr_type)][0]["delete"]=False
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ input_dict_comm = {
+ "community": "500:500"
+ }
+
+ result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]],
+ input_dict_comm)
+ assert result is True, (
+ "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result))
+
+ write_test_footer(tc_name)
+
+
+def test_verify_cli_json_p1(request):
+ """
+ TC8_FUNC_9:
+ 1.5.9. Verifying the JSON outputs for all supported commands:
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ input_dict = {
+ "r1":{
+ "cli": ["show bgp vrf default ipv4 summary",
+ "show bgp vrf all ipv6 summary",
+ "show bgp neighbors"
+ ]
+ }
+ }
+
+ result = verify_cli_json(tgen, input_dict)
+ 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/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
new file mode 100755
index 0000000000..6c106060b8
--- /dev/null
+++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py
@@ -0,0 +1,962 @@
+#!/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 Dynamic Route Leaking:
+
+1. Verify that Changing route-map configurations(match/set clauses) on
+ the fly it takes immediate effect.
+2. Verify BGP best path selection algorithm works fine when
+ routes are imported from ISR to default vrf and vice versa.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+import platform
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+sys.path.append(os.path.join(CWD, '../lib/'))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+from mininet.topo import Topo
+
+from lib.common_config import (
+ start_topology, write_test_header, check_address_types,
+ write_test_footer,
+ verify_rib, step, create_route_maps,
+ create_static_routes, stop_router, start_router,
+ create_prefix_lists,
+ create_bgp_community_lists,
+ check_router_status,
+ get_frr_ipv6_linklocal,
+ shutdown_bringup_interface
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence, create_router_bgp,
+ verify_bgp_community, verify_bgp_attributes,
+ verify_best_path_as_per_bgp_attribute, verify_bgp_rib
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/bgp_vrf_dynamic_route_leak_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": "11.11.11.1/32", "ipv6": "11:11::1/128"}
+NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"}
+NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"}
+
+PREFERRED_NEXT_HOP = "global"
+
+
+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
+ """
+
+ global topo
+ testsuite_run_time = time.asctime(time.localtime(time.time()))
+ logger.info("Testsuite start time: {}".format(testsuite_run_time))
+ logger.info("=" * 40)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ tgen = Topogen(CreateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Run these tests for kernel version 4.19 or above
+ if version_cmp(platform.release(), '4.19') < 0:
+ error_msg = ('BGP vrf dynamic route leak tests will not run '
+ '(have kernel "{}", but it requires >= 4.19)'.\
+ format(platform.release()))
+ pytest.skip(error_msg)
+
+ # 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_bgp_best_path_with_dynamic_import_p0(request):
+ """
+ TC6_FUNC_6:
+ 1.5.6. Verify BGP best path selection algorithm works fine when
+ routes are imported from ISR to default vrf and vice versa.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Redistribute configured static routes into BGP process"
+ " on R1/R2 and R3")
+
+ input_dict_1={}
+ DUT = ["r1", "r2", "r3", "r4"]
+ VRFS = ["ISR", "ISR", "default", "default"]
+ AS_NUM = [100, 100, 300, 400]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static"
+ }]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Import from default vrf into vrf ISR on R1 and R2 as below")
+
+ input_dict_vrf={}
+ DUT = ["r1", "r2"]
+ VRFS = ["ISR", "ISR"]
+ AS_NUM = [100, 100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_vrf.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "default"
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ input_dict_default={}
+ DUT = ["r1", "r2"]
+ VRFS = ["default", "default"]
+ AS_NUM = [100, 100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_default.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_default)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ step("Verify ECMP/Next-hop/Imported routes Vs Locally originated "
+ "routes/eBGP routes vs iBGP routes --already covered in almost"
+ " all tests")
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify Pre-emption")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type]
+ ]
+ }]
+ }
+ }
+
+ intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
+ intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
+
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
+ nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
+ else:
+ nh_r3_r1 = topo["routers"]["r3"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+ nh_r4_r1 = topo["routers"]["r4"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3,
+ next_hop=[nh_r4_r1])
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result))
+
+ step("Shutdown interface connected to r1 from r4:")
+ shutdown_bringup_interface(tgen, 'r4', intf_r4_r1, False)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type]
+ ]
+ }]
+ }
+ }
+
+ intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
+ intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
+
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
+ nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
+ else:
+ nh_r3_r1 = topo["routers"]["r3"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+ nh_r4_r1 = topo["routers"]["r4"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+
+ step("Verify next-hop is changed")
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3,
+ next_hop=[nh_r3_r1])
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result))
+
+ step("Bringup interface connected to r1 from r4:")
+ shutdown_bringup_interface(tgen, 'r4', intf_r4_r1, True)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type]
+ ]
+ }]
+ }
+ }
+
+ intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"]
+ intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"]
+
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1)
+ nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1)
+ else:
+ nh_r3_r1 = topo["routers"]["r3"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+ nh_r4_r1 = topo["routers"]["r4"]["links"]\
+ ["r1-link1"][addr_type].split("/")[0]
+
+ step("Verify next-hop is not chnaged aftr shutdown:")
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r3,
+ next_hop=[nh_r3_r1])
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result))
+
+ step("Active-Standby scenario(as-path prepend and Local pref)")
+
+ for addr_type in ADDR_TYPES:
+
+ step("Create prefix-list")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pf_ls_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK3_4[addr_type],
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Create route-map to match prefix-list and set localpref 500")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_PATH1_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_ls_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "locPrf": 500
+ }
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ step("Create route-map to match prefix-list and set localpref 600")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_PATH2_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 20,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_ls_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "locPrf": 600
+ }
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ input_dict_rma={
+ "r1": {
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_PATH1_{}".\
+ format(addr_type),
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [{
+ "name": "rmap_PATH2_{}".\
+ format(addr_type),
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]}
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_rma)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ dut = "r1"
+ attribute = "locPrf"
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify bestpath is installed as per highest localpref")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
+ input_routes_r3,
+ attribute)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Create route-map to match prefix-list and set localpref 700")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_PATH1_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_ls_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "locPrf": 700
+ }
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify bestpath is changed as per highest localpref")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
+ input_routes_r3,
+ attribute)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Create route-map to match prefix-list and set as-path prepend")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_PATH2_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 20,
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pf_ls_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "localpref": 700,
+ "path": {
+ "as_num": "111",
+ "as_action": "prepend"
+ }
+ }
+ }]
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ attribute = "path"
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify bestpath is changed as per shortest as-path")
+
+ input_routes_r3 = {
+ "r3": {
+ "static_routes": [{
+ "network": [
+ NETWORK3_3[addr_type], \
+ NETWORK3_4[addr_type]
+ ]
+ }]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(tgen, addr_type, dut,
+ input_routes_r3,
+ attribute)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_modify_route_map_match_set_clauses_p1(request):
+ """
+ TC13_CHAOS_4:
+ 1.5.13. Verify that Changing route-map configurations(match/set clauses) on
+ the fly it takes immediate effect.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ build_config_from_json(tgen, topo)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure route-map to set community attribute for a specific"
+ "prefix on R1 in vrf ISR")
+
+ input_dict_pf = {
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_ABC_{}".format(addr_type): [{
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit"
+ }]
+ }
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_pf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result)
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100"
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_XYZ_{}".format(addr_type): [{
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists":
+ "pflist_ABC_{}".format(addr_type)
+ }
+ },
+ "set": {
+ "community": {"num": "100:100"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply this route-map on R1 to vrf ISR while redistributing the"
+ " prefixes into BGP")
+
+ input_dict_1={}
+ DUT = ["r1"]
+ VRFS = ["ISR"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_1.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "route-map" : "rmap_XYZ_{}".\
+ format(addr_type)
+ }
+ }
+ ]
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} :Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Configure another route-map for filtering the prefixes based on"
+ " community attribute while importing into default vrf")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "community": {"num": "none"}
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Apply the route-map while Importing vrf ISR's prefixes into "
+ "default vrf on router R1:")
+
+ input_dict_isr={}
+ DUT = ["r1"]
+ VRFS = ["default"]
+ AS_NUM = [100]
+
+ for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM):
+ temp = {dut: {"bgp": []}}
+ input_dict_isr.update(temp)
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "ISR"
+ }
+ }
+ }
+ }
+ })
+
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "import": {
+ "vrf": "route-map rmap_IMP_{}".format(addr_type)
+ }
+ }
+ }
+ }
+ })
+
+ result = create_router_bgp(tgen, topo, input_dict_isr)
+ assert result is True, "Testcase {} : Failed \n Error: {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify on R1 that only prefixes with community value 100:100"
+ "in vrf ISR are imported to vrf default. While importing, the"
+ " community value has been stripped off:")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1)
+ assert result is True, \
+ "Testcase {} : Failed \n Error {}". \
+ format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Add set clause in route-map IMP:")
+
+ input_dict_rm = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [{
+ "action": "permit",
+ "seq_id": 10,
+ "match": {
+ "community_list": {"id": "COMM"}
+ },
+ "set": {
+ "large_community": {"num": "100:100:100"},
+ "locPrf": 500,
+ "path": {
+ "as_num": "100 100",
+ "as_action": "prepend"
+ }
+ }
+ }]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ step("Verify that as we continue adding different attributes "
+ "step-by-step in route-map IMP those attributes gets "
+ "attached to prefixes:")
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ input_dict_comm = {
+ "largeCommunity": "100:100:100"
+ }
+
+ result = verify_bgp_community(tgen, addr_type, dut, [NETWORK1_1[addr_type]],
+ input_dict_comm)
+ assert result is True, (
+ "Testcase {} : Failed \n Error {}".format(
+ tc_name, result))
+
+ input_rmap = {
+ "r1": {
+ "route_maps": {
+ "rmap_IMP_{}".format(addr_type): [
+ {
+ "set": {
+ "locPrf": 500
+ }
+ }
+ ]
+ }
+ }
+ }
+
+ result = verify_bgp_attributes(tgen, addr_type, "r1",\
+ [NETWORK1_1[addr_type]],
+ rmap_name="rmap_IMP_{}".format(addr_type),\
+ input_dict=input_rmap)
+ assert result is True, "Testcase : Failed \n Error: {}".format(
+ tc_name, result)
+
+ step("Change community-list to match a different value then "
+ "100:100.")
+
+ input_dict_cl = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "expanded",
+ "action": "permit",
+ "name": "COMM",
+ "value": "100:100",
+ "delete": True
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_cl)
+ assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
+ tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": [
+ NETWORK1_1[addr_type]
+ ],
+ "vrf": "default"
+ }]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_routes_r1,
+ expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Error : Routes are still "
+ "present {}".\
+ format(tc_name, result))
+
+ 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 316d4cf414..e2f887bb89 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -456,6 +456,15 @@ def __create_bgp_unicast_neighbor(
cmd = "no {}".format(cmd)
config_data.append(cmd)
+ import_vrf_data = addr_data.setdefault("import", {})
+ if import_vrf_data:
+ cmd = "import vrf {}".format(import_vrf_data["vrf"])
+
+ del_action = import_vrf_data.setdefault("delete", False)
+ if del_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
if "neighbor" in addr_data:
neigh_data = __create_bgp_neighbor(
topo, input_dict, router, addr_type, add_neigh
@@ -2610,6 +2619,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
if not isinstance(next_hop, list):
next_hop = [next_hop]
list1 = next_hop
+
found_hops = [
rib_r["ip"]
for rib_r in rib_routes_json["routes"][st_rt][0][
@@ -2617,6 +2627,7 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
]
]
list2 = found_hops
+
missing_list_of_nexthops = set(list2).difference(list1)
additional_nexthops_in_required_nhs = set(
list1
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index d77946b1ed..1846d43138 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -32,6 +32,7 @@ from tempfile import mkdtemp
import os
import sys
+import ConfigParser
import traceback
import socket
import ipaddress
@@ -1237,7 +1238,8 @@ def interface_status(tgen, topo, input_dict):
return True
-def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict=False):
+def retry(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
@@ -1249,11 +1251,13 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict
"""
def _retry(func):
+
@wraps(func)
def func_retry(*args, **kwargs):
- _wait = kwargs.pop("wait", wait)
- _attempts = kwargs.pop("attempts", attempts)
+ _wait = kwargs.pop('wait', wait)
+ _attempts = kwargs.pop('attempts', attempts)
_attempts = int(_attempts)
+ expected = True
if _attempts < 0:
raise ValueError("attempts must be 0 or greater")
@@ -1261,40 +1265,40 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0, return_is_dict
logger.info("Waiting for [%s]s as initial delay", initial_wait)
sleep(initial_wait)
- _return_is_str = kwargs.pop("return_is_str", return_is_str)
- _return_is_dict = kwargs.pop("return_is_str", return_is_dict)
+ _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")
+ _expected = kwargs.setdefault('expected', True)
+ if _expected is False:
+ expected = _expected
+ kwargs.pop('expected')
ret = func(*args, **kwargs)
- logger.debug("Function returned %s" % ret)
+ logger.debug("Function returned %s", ret)
if _return_is_str and isinstance(ret, bool) and _expected:
return ret
- if (
- isinstance(ret, str) or isinstance(ret, unicode)
- ) and _expected is False:
+ 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:
+ if _attempts == i and expected:
generate_support_bundle()
return ret
except Exception as err:
- if _attempts == i:
+ if _attempts == i and expected:
generate_support_bundle()
- logger.info("Max number of attempts (%r) reached", _attempts)
+ logger.info("Max number of attempts (%r) reached",
+ _attempts)
raise
else:
logger.info("Function returned %s", err)
if i < _attempts:
- logger.info("Retry [#%r] after sleeping for %ss" % (i, _wait))
+ logger.info("Retry [#%r] after sleeping for %ss"
+ % (i, _wait))
sleep(_wait)
-
func_retry._original = func
return func_retry
-
return _retry
@@ -2517,7 +2521,7 @@ def verify_rib(
errormsg(str) or True
"""
- logger.info("Entering lib API: verify_rib()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
router_list = tgen.routers()
additional_nexthops_in_required_nhs = []
@@ -2832,7 +2836,263 @@ def verify_rib(
" routes are: {}\n".format(addr_type, dut, found_routes)
)
- logger.info("Exiting lib API: verify_rib()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+def verify_fib_routes(tgen, addr_type, dut, input_dict, next_hop=None):
+ """
+ Data will be read from input_dict or input JSON file, API will generate
+ same prefixes, which were redistributed by either create_static_routes() or
+ advertise_networks_using_network_command() and will verify next_hop and
+ each prefix/routes is present in "show ip/ipv6 fib json"
+ command o/p.
+
+ Parameters
+ ----------
+ * `tgen` : topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test, for which user wants to test the data
+ * `input_dict` : input dict, has details of static routes
+ * `next_hop`[optional]: next_hop which needs to be verified,
+ default: static
+
+ Usage
+ -----
+ input_routes_r1 = {
+ "r1": {
+ "static_routes": [{
+ "network": ["1.1.1.1/32],
+ "next_hop": "Null0",
+ "vrf": "RED"
+ }]
+ }
+ }
+ result = result = verify_fib_routes(tgen, "ipv4, "r1", input_routes_r1)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ router_list = tgen.routers()
+ for routerInput in input_dict.keys():
+ for router, rnode in router_list.iteritems():
+ if router != dut:
+ continue
+
+ logger.info("Checking router %s FIB routes:", router)
+
+ # Verifying RIB routes
+ if addr_type == "ipv4":
+ command = "show ip fib"
+ else:
+ command = "show ipv6 fib"
+
+ found_routes = []
+ missing_routes = []
+
+ if "static_routes" in input_dict[routerInput]:
+ static_routes = input_dict[routerInput]["static_routes"]
+
+ for static_route in static_routes:
+ if "vrf" in static_route and static_route["vrf"] is not None:
+
+ logger.info(
+ "[DUT: {}]: Verifying routes for VRF:"
+ " {}".format(router, static_route["vrf"])
+ )
+
+ cmd = "{} vrf {}".format(command, static_route["vrf"])
+
+ else:
+ cmd = "{}".format(command)
+
+ cmd = "{} json".format(cmd)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if bool(rib_routes_json) is False:
+ errormsg = "[DUT: {}]: No route found in fib".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
+
+ # 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(ipaddress.ip_network(unicode(st_rt)))
+ #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 len(missing_routes) > 0:
+ errormsg = "[DUT: {}]: Missing route in FIB:" " {}".format(
+ dut, missing_routes
+ )
+ return errormsg
+
+ if nh_found:
+ logger.info(
+ "Found next_hop {} for all routes in RIB"
+ " of router {}\n".format(next_hop, dut)
+ )
+
+ if found_routes:
+ logger.info(
+ "[DUT: %s]: Verified routes in FIB, found" " routes are: %s\n",
+ dut,
+ found_routes,
+ )
+
+ continue
+
+ if "bgp" in input_dict[routerInput]:
+ if (
+ "advertise_networks"
+ 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"]
+
+ # 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)))
+ st_rt = str(ipaddress.ip_network(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 len(missing_routes) > 0:
+ errormsg = "[DUT: {}]: Missing route in FIB: " "{} \n".format(
+ dut, missing_routes
+ )
+ return errormsg
+
+ if nh_found:
+ logger.info(
+ "Found next_hop {} for all routes in RIB"
+ " of router {}\n".format(next_hop, dut)
+ )
+
+ if found_routes:
+ logger.info(
+ "[DUT: {}]: Verified routes FIB"
+ ", found routes are: {}\n".format(dut, found_routes)
+ )
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True