diff options
Diffstat (limited to 'tests/topotests/bgp_large_community')
5 files changed, 4068 insertions, 0 deletions
diff --git a/tests/topotests/bgp_large_community/__init__.py b/tests/topotests/bgp_large_community/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/topotests/bgp_large_community/__init__.py diff --git a/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json b/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json new file mode 100644 index 0000000..902c01b --- /dev/null +++ b/tests/topotests/bgp_large_community/bgp_large_community_topo_1.json @@ -0,0 +1,262 @@ +{ + "ipv4base": "192.168.1.0", + "ipv4mask": 24, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "192.168.1.0", + "v4mask": 24, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {} + } + }, + "r3": { + "dest_link": { + "r1-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {} + } + }, + "r3": { + "dest_link": { + "r1-link1": {} + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "1000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {} + } + }, + "r4": { + "dest_link": { + "r2-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {} + } + }, + "r4": { + "dest_link": { + "r2-link1": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "4000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": {} + } + }, + "r5": { + "dest_link": { + "r4-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": {} + } + }, + "r5": { + "dest_link": { + "r4-link1": {} + } + } + } + } + } + } + } + }, + "r5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r4-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "6000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r5-link1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r5-link1": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json b/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json new file mode 100644 index 0000000..36dee39 --- /dev/null +++ b/tests/topotests/bgp_large_community/bgp_large_community_topo_2.json @@ -0,0 +1,344 @@ +{ + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "1000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {} + } + }, + "r3": { + "dest_link": { + "r1": {} + } + } + } + } + } + } + } + }, + "r2": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "1000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r4": { + "dest_link": { + "r2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {} + } + }, + "r4": { + "dest_link": { + "r2": {} + } + } + } + } + } + } + } + }, + "r3": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {} + } + }, + "r5": { + "dest_link": { + "r3": {} + } + } + } + } + } + } + } + }, + "r4": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r6": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "4000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": {} + } + }, + "r6": { + "dest_link": { + "r4": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": {} + } + }, + "r6": { + "dest_link": { + "r4": {} + } + } + } + } + } + } + } + }, + "r5": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r3": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r6": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "5000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + }, + "r6": { + "dest_link": { + "r5": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5": {} + } + }, + "r6": { + "dest_link": { + "r5": {} + } + } + } + } + } + } + } + }, + "r6": { + "links": { + "lo": { + "ipv4": "auto", + "ipv6": "auto", + "type": "loopback" + }, + "r4": { + "ipv4": "auto", + "ipv6": "auto" + }, + "r5": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": { + "local_as": "6000000", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": {} + } + }, + "r5": { + "dest_link": { + "r6": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": {} + } + }, + "r5": { + "dest_link": { + "r6": {} + } + } + } + } + } + } + } + } + } +} diff --git a/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py new file mode 100644 index 0000000..03cfded --- /dev/null +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_1.py @@ -0,0 +1,1229 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2019 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 large-community/community functionality: +1. Verify if large community attribute can be configured only in correct + canonical format. +2. Verify that the community attribute value, which we have advertised are + received in correct format and values, at the receiving end. +3. Verify BGP Large Community attribute"s transitive property attribute. +4. Verify that BGP Large Communities attribute are malformed, if the length of + the BGP Large Communities Attribute value, expressed in octets, + is not a non-zero multiple of 12. +5. Verify if overriding large community values works fine. +6. Verify that large community values" aggregation works fine. +7. Standard community also work fine in conjunction with large-community. +8. Matching prefixes based on attributes other than prefix list and make use + of set clause (IPV6). +9. Matching prefixes based on attributes other than prefix list and make use + of set clause (IPV4). +10. Verify community and large-community list operations in route-map with all + clause (exact, all, any, regex) works. +11. Verify that any value in BGP Large communities for boundary values. +12. Clear BGP neighbor-ship and check if large community and community + attributes are getting re-populated. + +""" + +import pytest +import time +from os import path as os_path +import sys + +# Required to instantiate the topology builder class. +from lib.topogen import Topogen, get_topogen + +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + create_route_maps, + create_bgp_community_lists, + create_prefix_lists, + verify_bgp_community, + step, + check_address_types, + required_linux_kernel_version, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp_and_verify +from lib.topojson import build_config_from_json + +pytestmark = [pytest.mark.bgpd] + + +# 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/")) + + +# Global variables +bgp_convergence = False +NETWORK = { + "ipv4": ["200.50.2.0", "200.50.2.1", "200.50.2.0"], + "ipv6": ["1::1", "1::2", "1::0"], +} +MASK = {"ipv4": "32", "ipv6": "128"} +NET_MASK = {"ipv4": "24", "ipv6": "120"} +IPV4_NET = ["200.50.2.0"] +IPV6_NET = ["1::0"] +CONFIG_ROUTER_R1 = False +CONFIG_ROUTER_R2 = False +CONFIG_ROUTER_ADDITIVE = False +ADDR_TYPES = [] +LARGE_COMM = { + "r1": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1", + "r2": "2:1:1 2:2:1 2:3:1 2:4:1 2:5:1", + "mal_1": "1:1 1:2 1:3 1:4 1:5", + "pf_list_1": "0:0:1 0:0:10 0:0:100", + "pf_list_2": "0:0:2 0:0:20 0:0:200", + "agg_1": "0:0:1 0:0:2 0:0:10 0:0:20 0:0:100 0:0:200 2:1:1 " + "2:2:1 2:3:1 2:4:1 2:5:1", + "agg_2": "0:0:2 0:0:20 0:0:200 2:1:1 " "2:2:1 2:3:1 2:4:1 2:5:1", +} +STANDARD_COMM = { + "r1": "1:1 1:2 1:3 1:4 1:5", + "r2": "2:1 2:2 2:3 2:4 2:5", + "mal_1": "1 2 3 4 5", + "pf_list_1": "0:1 0:10 0:100", + "pf_list_2": "0:2 0:20 0:200", + "agg_1": "0:1 0:2 0:10 0:20 0:100 0:200 2:1 2:2 2:3 2:4 2:5", + "agg_2": "0:2 0:20 0:200 2:1 2:2 2:3 2:4 2:5", +} + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + global ADDR_TYPES + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_large_community_topo_1.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start daemons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + ##tgen.mininet_cli() + # Api call verify whether BGP is converged + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "setup_module :Failed \n Error:" " {}".format( + bgp_convergence + ) + + ADDR_TYPES = check_address_types() + logger.info("Running setup_module() done") + + +def teardown_module(): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def config_router_r1(tgen, topo, tc_name): + global CONFIG_ROUTER_R1 + + input_dict_1 = { + "r1": { + "route_maps": { + "LC1": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": {"num": LARGE_COMM["r1"]}, + "community": {"num": STANDARD_COMM["r1"]}, + }, + } + ] + } + } + } + + step("Configuring LC1 on r1") + result = create_route_maps(tgen, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + # Configure neighbor for route map + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + { + "network": "%s/%s" + % (NETWORK["ipv4"][0], MASK["ipv4"]), + "no_of_network": 4, + } + ], + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": { + "route_maps": [ + {"name": "LC1", "direction": "out"} + ] + } + } + }, + "r3": { + "dest_link": { + "r1-link1": { + "route_maps": [ + {"name": "LC1", "direction": "out"} + ] + } + } + }, + }, + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "%s/%s" + % (NETWORK["ipv6"][0], MASK["ipv6"]), + "no_of_network": 4, + } + ], + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": { + "route_maps": [ + {"name": "LC1", "direction": "out"} + ] + } + } + }, + "r3": { + "dest_link": { + "r1-link1": { + "route_maps": [ + {"name": "LC1", "direction": "out"} + ] + } + } + }, + }, + } + }, + } + } + } + } + + step("Applying LC1 on r1 neighbors and advertising networks") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + CONFIG_ROUTER_R1 = True + + +def config_router_r2(tgen, topo, tc_name): + global CONFIG_ROUTER_R2 + + input_dict = { + "r2": { + "route_maps": { + "LC2": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": {"num": LARGE_COMM["r2"]}, + "community": {"num": STANDARD_COMM["r2"]}, + }, + } + ] + } + } + } + + step("Configuring route-maps LC2 on r2") + result = create_route_maps(tgen, input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + input_dict_1 = { + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [ + {"name": "LC2", "direction": "out"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [ + {"name": "LC2", "direction": "out"} + ] + } + } + } + } + } + }, + } + } + } + } + + step("Applying LC2 on r2 neighbors in out direction") + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + CONFIG_ROUTER_R2 = True + + +def config_router_additive(tgen, topo, tc_name): + global CONFIG_ROUTER_ADDITIVE + + input_dict = { + "r2": { + "route_maps": { + "LC2": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": LARGE_COMM["r2"], + "action": "additive", + }, + "community": { + "num": STANDARD_COMM["r2"], + "action": "additive", + }, + }, + } + ] + } + } + } + + step("Configuring LC2 with community attributes as additive") + result = create_route_maps(tgen, input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + # tgen.mininet_cli() + CONFIG_ROUTER_ADDITIVE = True + + +def config_for_as_path(tgen, topo, tc_name): + config_router_r1(tgen, topo, tc_name) + + config_router_r2(tgen, topo, tc_name) + + # Create ipv6 prefix list + input_dict_1 = { + "r1": { + "prefix_lists": { + "ipv4": { + "pf_list_1": [ + { + "seqid": "10", + "network": "%s/%s" % (NETWORK["ipv4"][0], MASK["ipv4"]), + "action": "permit", + } + ], + "pf_list_2": [ + { + "seqid": "10", + "network": "%s/%s" % (NETWORK["ipv4"][1], MASK["ipv4"]), + "action": "permit", + } + ], + }, + "ipv6": { + "pf_list_3": [ + { + "seqid": "10", + "network": "%s/%s" % (NETWORK["ipv6"][0], MASK["ipv6"]), + "action": "permit", + } + ], + "pf_list_4": [ + { + "seqid": "10", + "network": "%s/%s" % (NETWORK["ipv6"][1], MASK["ipv6"]), + "action": "permit", + } + ], + }, + } + } + } + + step("Configuring prefix-lists on r1 to filter networks") + result = create_prefix_lists(tgen, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + input_dict_2 = { + "r1": { + "route_maps": { + "LC1": [ + { + "action": "permit", + "seq_id": 10, + "match": {"ipv4": {"prefix_lists": "pf_list_1"}}, + "set": { + "large_community": {"num": LARGE_COMM["pf_list_1"]}, + "community": {"num": STANDARD_COMM["pf_list_1"]}, + }, + }, + { + "action": "permit", + "seq_id": 20, + "match": {"ipv6": {"prefix_lists": "pf_list_3"}}, + "set": { + "large_community": {"num": LARGE_COMM["pf_list_1"]}, + "community": {"num": STANDARD_COMM["pf_list_1"]}, + }, + }, + { + "action": "permit", + "seq_id": 30, + "match": {"ipv4": {"prefix_lists": "pf_list_2"}}, + "set": { + "large_community": {"num": LARGE_COMM["pf_list_2"]}, + "community": {"num": STANDARD_COMM["pf_list_2"]}, + }, + }, + { + "action": "permit", + "seq_id": 40, + "match": {"ipv6": {"prefix_lists": "pf_list_4"}}, + "set": { + "large_community": {"num": LARGE_COMM["pf_list_2"]}, + "community": {"num": STANDARD_COMM["pf_list_2"]}, + }, + }, + ] + } + } + } + + step( + "Applying prefix-lists match in route-map LC1 on r1. Setting" + " community attritbute for filtered networks" + ) + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + config_router_additive(tgen, topo, tc_name) + + input_dict_3 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": LARGE_COMM["pf_list_1"], + "large": True, + }, + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": STANDARD_COMM["pf_list_1"], + }, + ] + } + } + + step("Configuring bgp community lists on r4") + result = create_bgp_community_lists(tgen, input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + input_dict_4 = { + "r4": { + "route_maps": { + "LC4": [ + { + "action": "permit", + "seq_id": "10", + "match": { + "large_community_list": {"id": "ANY"}, + "community_list": {"id": "ANY"}, + }, + "set": {"path": {"as_num": "4000000", "as_action": "prepend"}}, + } + ] + } + } + } + + step("Applying community list on route-map on r4") + result = create_route_maps(tgen, input_dict_4) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + input_dict_5 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r4-link1": { + "route_maps": [ + {"name": "LC4", "direction": "out"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r4-link1": { + "route_maps": [ + {"name": "LC4", "direction": "out"} + ] + } + } + } + } + } + }, + } + } + } + } + + step("Applying route-map LC4 out from r4 to r5 ") + result = create_router_bgp(tgen, topo, input_dict_5) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + +##################################################### +# +# Test cases +# +##################################################### +def test_large_community_set(request): + """ + Verify if large community attribute can be configured only in correct + canonical format. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # API call to modify router id + # input_dict dictionary to be provided to configure route_map + input_dict = { + "r1": { + "route_maps": { + "LC1": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": {"num": LARGE_COMM["r1"]}, + "community": {"num": STANDARD_COMM["r1"]}, + }, + } + ] + } + } + } + + step("Trying to set bgp communities") + result = create_route_maps(tgen, input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_large_community_advertise(request): + """ + Verify that the community attribute value, which we have advertised are + received in correct format and values, at the receiving end. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + input_dict = { + "largeCommunity": LARGE_COMM["r1"], + "community": STANDARD_COMM["r1"], + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]], input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + result = verify_bgp_community(tgen, adt, "r3", [NETWORK[adt][0]], input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_transitive(request): + """ + Verify BGP Large Community attribute"s transitive property attribute. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + config_router_r1(tgen, topo, tc_name) + + input_dict_1 = { + "largeCommunity": LARGE_COMM["r1"], + "community": STANDARD_COMM["r1"], + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]], input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_override(request): + """ + Verify if overriding large community values works fine. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + config_router_r2(tgen, topo, tc_name) + + input_dict_3 = { + "largeCommunity": LARGE_COMM["r2"], + "community": STANDARD_COMM["r2"], + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][1]], input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_additive(request): + """ + Verify that large community values" aggregation works fine. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + config_router_r2(tgen, topo, tc_name) + + config_router_additive(tgen, topo, tc_name) + + input_dict_1 = { + "largeCommunity": "%s %s" % (LARGE_COMM["r1"], LARGE_COMM["r2"]), + "community": "%s %s" % (STANDARD_COMM["r1"], STANDARD_COMM["r2"]), + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]], input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_match_as_path(request): + """ + Matching prefixes based on attributes other than prefix list and make use + of set clause. + """ + + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_for_as_path(tgen, topo, tc_name) + + input_dict = { + "largeCommunity": "%s %s" % (LARGE_COMM["pf_list_1"], LARGE_COMM["r2"]), + "community": "%s %s" % (STANDARD_COMM["pf_list_1"], STANDARD_COMM["r2"]), + } + + input_dict_1 = { + "largeCommunity": "%s %s" % (LARGE_COMM["pf_list_2"], LARGE_COMM["r2"]), + "community": "%s %s" % (STANDARD_COMM["pf_list_2"], STANDARD_COMM["r2"]), + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r5", [NETWORK[adt][0]], input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + result = verify_bgp_community( + tgen, adt, "r5", [NETWORK[adt][1]], input_dict_1, expected=False + ) + + assert result is not True, "Test case {} : Should fail \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_match_all(request): + """ + Verify community and large-community list operations in route-map with all + clause (exact, all, any, regex) works. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + config_router_r2(tgen, topo, tc_name) + + config_router_additive(tgen, topo, tc_name) + + input_dict_1 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "1:1:1", + "large": True, + }, + { + "community_type": "standard", + "action": "permit", + "name": "ALL", + "value": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:1:1 2:2:1", + "large": True, + }, + { + "community_type": "expanded", + "action": "permit", + "name": "EXP_ALL", + "value": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:[1-5]:1", + "large": True, + }, + ] + } + } + + step("Create bgp community lists for ANY, EXACT and EXP_ALL match") + + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + input_dict_2 = { + "r4": { + "route_maps": { + "LC4": [ + { + "action": "permit", + "seq_id": "10", + "match": {"large-community-list": {"id": "ANY"}}, + }, + { + "action": "permit", + "seq_id": "20", + "match": {"large-community-list": {"id": "EXACT"}}, + }, + { + "action": "permit", + "seq_id": "30", + "match": {"large-community-list": {"id": "EXP_ALL"}}, + }, + ] + } + } + } + + step("Applying bgp community lits on LC4 route-map") + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + input_dict_3 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r4-link1": { + "route_maps": [ + {"name": "LC4", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r5": { + "dest_link": { + "r4-link1": { + "route_maps": [ + {"name": "LC4", "direction": "in"} + ] + } + } + } + } + } + }, + } + } + } + } + + step("Apply route-mpa LC4 on r4 for r2 neighbor, direction 'in'") + + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + input_dict_4 = { + "largeCommunity": "1:1:1 1:2:1 1:3:1 1:4:1 1:5:1 2:1:1 2:2:1 2:3:1 " + "2:4:1 2:5:1" + } + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r4", [NETWORK[adt][0]], input_dict_4) + assert result is True, "Test case {} : Should fail \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +# @pytest.mark.skip(reason="as-set not working for ipv6") +def test_large_community_aggregate_network(request): + """ + Restart router and check if large community and community + attributes are getting re-populated. + """ + + tc_name = request.node.name + write_test_header(tc_name) + + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + config_for_as_path(tgen, topo, tc_name) + + input_dict = { + "community": STANDARD_COMM["agg_1"], + "largeCommunity": LARGE_COMM["agg_1"], + } + + input_dict_1 = { + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "aggregate_address": [ + { + "network": "%s/%s" + % (NETWORK["ipv4"][2], NET_MASK["ipv4"]), + "as_set": True, + } + ] + } + }, + "ipv6": { + "unicast": { + "aggregate_address": [ + { + "network": "%s/%s" + % (NETWORK["ipv6"][2], NET_MASK["ipv6"]), + "as_set": True, + } + ] + } + }, + } + } + } + } + + step("Configuring aggregate address as-set on r2") + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + for adt in ADDR_TYPES: + result = verify_bgp_community( + tgen, adt, "r4", ["%s/%s" % (NETWORK[adt][2], NET_MASK[adt])], input_dict + ) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + { + "network": "%s/%s" + % (NETWORK["ipv4"][0], MASK["ipv4"]), + "no_of_network": 1, + "delete": True, + } + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + { + "network": "%s/%s" + % (NETWORK["ipv6"][0], MASK["ipv6"]), + "no_of_network": 1, + "delete": True, + } + ] + } + }, + } + } + } + } + + step("Stop advertising one of the networks") + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Test case {} : Failed \n Error: {}".format(tc_name, result) + + input_dict_3 = { + "community": STANDARD_COMM["agg_2"], + "largeCommunity": LARGE_COMM["agg_2"], + } + + for adt in ADDR_TYPES: + step("Verifying bgp community values on r5 is also modified") + result = verify_bgp_community( + tgen, adt, "r4", ["%s/%s" % (NETWORK[adt][2], NET_MASK[adt])], input_dict_3 + ) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_boundary_values(request): + """ + Verify that any value in BGP Large communities for boundary values. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "0:-1", + } + ] + } + } + + step("Checking boundary value for community 0:-1") + result = create_bgp_community_lists(tgen, input_dict) + assert result is not True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Checking community attribute 0:65536") + input_dict_2 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "0:65536", + } + ] + } + } + + step("Checking boundary value for community 0:65536") + result = create_bgp_community_lists(tgen, input_dict_2) + assert result is not True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Checking boundary value for community 0:4294967296") + input_dict_3 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "0:4294967296", + "large": True, + } + ] + } + } + + result = create_bgp_community_lists(tgen, input_dict_3) + assert result is not True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + step("Checking boundary value for community 0:-1:1") + + input_dict_4 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "0:-1:1", + "large": True, + } + ] + } + } + + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is not True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + +def test_large_community_invalid_chars(request): + """ + BGP canonical lcommunities must only be digits + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "1:a:2", + "large": True, + } + ] + } + } + + step("Checking boundary value for community 1:a:2") + result = create_bgp_community_lists(tgen, input_dict) + assert result is not True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + +def test_large_community_after_clear_bgp(request): + """ + Clear BGP neighbor-ship and check if large community and community + attributes are getting re-populated. + """ + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + config_router_r1(tgen, topo, tc_name) + + input_dict = {"largeCommunity": LARGE_COMM["r1"], "community": STANDARD_COMM["r1"]} + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]], input_dict) + assert result is True, "Test case {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Clearing BGP on r1") + clear_bgp_and_verify(tgen, topo, "r1") + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, "r2", [NETWORK[adt][0]], input_dict) + 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_large_community/test_bgp_large_community_topo_2.py b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py new file mode 100644 index 0000000..b11cda3 --- /dev/null +++ b/tests/topotests/bgp_large_community/test_bgp_large_community_topo_2.py @@ -0,0 +1,2233 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2019 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. +# + +""" +test_bgp_large_community_topo_1.py: Test BGP large community. + +Following tests are covered: +1. Verify the standard large-community-lists can permit or deny + large community attribute only in the correct canonical format. +2. Verify the expanded large-community-lists can permit or deny + large community attribute both in the correct canonical format + as well as REG_EX. +3. Verify that we can modify a large-community-list is in use, + to add/remove attribute value and it takes immediate effect. +4. Verify that large community attribute gets advertised when + route-map is applied to a neighbor and cleared when route-map + is removed. +5. Verify that duplicate BGP Large Community values are NOT be transmitted. +6. Verify if we want to remove all the large-community attributes from a + set of prefix we can set the value as NONE. +7. Redistribute connected and static routes in BGP process with a route-map + appending/removing L-comm attributes. +8. Verify if we want to remove specific large-community values from + a set of prefix we can make use of DELETE operation based on L-comm list. +9. Verify that if community values are NOT be advertised to a specific + neighbour, we negate send-community command. + (Send-community all is enabled by default for all neighbors) +10. Verify that large-community lists can not be configured without providing + specific L-community values(for match/delete operation in a route-map). +11. Verify that Match_EXACT clause should pass only if all of the L-comm + values configured (horizontally) in the community list is present in + the prefix. There must be no additional L-communities in the prefix. +12. Verify that Match_ALL clause should pass only if ALL of the L-comm values + configured (horizontally) in the community list is present in the prefix. + There could be additional L-communities in the prefix that are not present + in the L-comm list. +13. Verify that Match_ANY clause should pass only if at-least any one L-comm + value configured(vertically) in large-community list, is present in prefixes. +14. Verify large-community lists operation in a route-map with match RegEx + statements. +""" + +import os +import sys +import pytest +import time + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +# Import topoJson from lib, to create topology and initial configuration +from lib.topogen import Topogen, get_topogen + +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + create_route_maps, + create_bgp_community_lists, + verify_bgp_community, + step, + verify_create_community_list, + delete_route_maps, + verify_route_maps, + create_static_routes, + check_address_types, + required_linux_kernel_version, +) +from lib.topolog import logger +from lib.bgp import verify_bgp_convergence, create_router_bgp, clear_bgp_and_verify +from lib.topojson import build_config_from_json + + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +bgp_convergence = False + +NETWORKS = {"ipv4": ["200.50.2.0/32"], "ipv6": ["1::1/128"]} + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_large_community_topo_2.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start daemons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Checking BGP convergence + global bgp_convergence, ADDR_TYPES + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + # Ipv4 + bgp_convergence = verify_bgp_convergence(tgen, topo) + assert bgp_convergence is True, "setup_module :Failed \n Error:" " {}".format( + bgp_convergence + ) + ADDR_TYPES = check_address_types() + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# +# Testcases +# +##################################################### + + +def test_create_bgp_standard_large_community_list(request): + """ + Create standard large-community-list and verify it can permit + or deny large community attribute only in the correct canonical + format. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + reset_config_on_routers(tgen) + + step("Create srtandard large community list") + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "LC_1_STD", + "value": "2:1:1 2:1:2 1:2:3", + "large": True, + }, + { + "community_type": "standard", + "action": "permit", + "name": "LC_2_STD", + "value": "3:1:1 3:1:2", + "large": True, + }, + ] + } + } + result = create_bgp_community_lists(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create srtandard large community list with in-correct values") + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "LC_1_STD_ERR", + "value": "0:0:0", + "large": True, + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + ## TODO should fail + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_create_bgp_expanded_large_community_list(request): + """ + Create expanded large-community-list and verify it can permit + or deny large community attribute both in the correct canonical + format as well as REG_EX + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create expanded large community list") + input_dict = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "expanded", + "action": "permit", + "name": "LC_1_EXP", + "value": "1:1:200 1:2:* 3:2:1", + "large": True, + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_modify_large_community_lists_referenced_by_rmap(request): + """ + This test is to verify that we can modify a large-community-list + is in use, add/remove attribute value and it takes immediate effect. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create standard large community list") + input_dict_1 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "LC_DEL", + "value": "1:2:1 1:3:1 2:1:1 2:2:2 3:3:3", + "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 map") + input_dict_2 = { + "r1": { + "route_maps": { + "RM_R2_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "1:2:1 1:3:1 2:10:1 3:3:3 4:4:4 5:5:5", + "action": "additive", + } + }, + } + ] + } + }, + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": {"large_comm_list": {"id": "LC_DEL", "delete": True}}, + } + ] + } + }, + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}], + "neighbor": { + "r2": { + "dest_link": { + "r1": { + "route_maps": [ + { + "name": "RM_R2_OUT", + "direction": "out", + } + ] + } + } + } + }, + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [{"network": "1::1/128"}], + "neighbor": { + "r2": { + "dest_link": { + "r1": { + "route_maps": [ + { + "name": "RM_R2_OUT", + "direction": "out", + } + ] + } + } + } + }, + } + }, + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify Community-list") + dut = "r4" + input_dict_4 = {"largeCommunity": "2:10:1 4:4:4 5:5:5"} + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_apply_and_remove(request): + """ + This test is to verify that large community attribute gets advertised when + route-map is applied to a neighbor and cleared when route-map is removed + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_1 = { + "r4": { + "route_maps": { + "RM_LC1": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "200:200:1 200:200:10 200:200:20000", + "action": "additive", + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_LC1", "direction": "out"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_LC1", "direction": "out"} + ] + } + } + } + } + } + }, + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify large-community-list") + dut = "r6" + input_dict_4 = {"largeCommunity": "200:200:1 200:200:10 200:200:20000"} + + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Delete route map reference by community-list") + input_dict_3 = {"r4": {"route_maps": ["RM_LC1"]}} + result = delete_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify route map is deleted") + result = verify_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify large-community-list") + for adt in ADDR_TYPES: + result = verify_bgp_community( + tgen, adt, dut, NETWORKS[adt], input_dict_4, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "largeCommunity is still present after deleting route-map \n Error: {}".format( + tc_name, result + ) + ) + + write_test_footer(tc_name) + + +def test_duplicate_large_community_list_attributes_not_transitive(request): + """ + This test is to verify that duplicate BGP Large Community values + are NOT be transmitted. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_1 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "0:0:1 0:0:10 0:0:100 2:0:1 2:0:2 2:0:3" + " 2:0:4 2:0:5", + "action": "additive", + } + }, + } + ], + "RM_R4_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "0:0:1 0:0:10 0:0:10000 2:0:1 2:0:2", + "action": "additive", + } + }, + } + ], + } + } + } + result = create_route_maps(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + }, + "r6": { + "dest_link": { + "r4": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + }, + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + }, + "r6": { + "dest_link": { + "r4": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + }, + } + } + }, + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify large-community-list") + dut = "r6" + input_dict_4 = { + "largeCommunity": "0:0:1 0:0:10 0:0:100 0:0:10000 2:0:1 2:0:2 2:0:3 2:0:4 2:0:5" + } + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_set_none(request): + """ + This test is to verify if we want to remove all the large-community + attributes from a set of prefix we can set the value as NONE. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_1 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "0:0:1 0:0:10 0:0:100 2:0:1 2:0:2 2:0:3" + " 2:0:4", + "action": "additive", + } + }, + } + ] + } + }, + "r6": { + "route_maps": { + "RM_R6_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": {"large_community": {"num": "none"}}, + } + ] + } + }, + } + result = create_route_maps(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map") + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + } + } + }, + "r6": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": { + "route_maps": [ + {"name": "RM_R6_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": { + "route_maps": [ + {"name": "RM_R6_IN", "direction": "in"} + ] + } + } + } + } + } + }, + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify Community-list") + dut = "r6" + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "Community-list is still present \n Error: {}".format(tc_name, result) + ) + + write_test_footer(tc_name) + + +def test_lcomm_lists_with_redistribute_static_connected_rmap(request): + """ + This test is to verify redistribute connected and static ipv4 routes + in BGP process with a route-map appending/removing L-comm attributes. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("create static routes") + input_dict = { + "r1": { + "static_routes": [ + {"network": "200.50.2.0/32", "next_hop": "10.0.0.6"}, + {"network": "1::1/128", "next_hop": "fd00:0:0:1::2"}, + ] + } + } + result = create_static_routes(tgen, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("redistribute static routes") + input_dict_1 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "redistribute": [ + { + "redist_type": "static", + "attribute": "route-map RM_R2_OUT", + }, + { + "redist_type": "connected", + "attribute": "route-map RM_R2_OUT", + }, + ] + } + }, + "ipv6": { + "unicast": { + "redistribute": [ + { + "redist_type": "static", + "attribute": "route-map RM_R2_OUT", + }, + { + "redist_type": "connected", + "attribute": "route-map RM_R2_OUT", + }, + ] + } + }, + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create route map") + input_dict_3 = { + "r1": { + "route_maps": { + "RM_R2_OUT": [ + { + "action": "permit", + "set": {"large_community": {"num": "55:55:55 555:555:555"}}, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify large-community-list for static and connected ipv4 route on" " r2") + + input_dict_5 = {"largeCommunity": "55:55:55 555:555:555"} + + if "ipv4" in ADDR_TYPES: + dut = "r2" + networks = ["200.50.2.0/32", "1.0.1.17/32"] + result = verify_bgp_community(tgen, "ipv4", dut, networks, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify large-community-list for static and connected ipv4 route" " on r4") + dut = "r4" + networks = ["200.50.2.0/32", "1.0.1.17/32"] + result = verify_bgp_community(tgen, "ipv4", dut, networks, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + if "ipv6" in ADDR_TYPES: + step("Verify large-community-list for static and connected ipv6 route" " on r2") + dut = "r2" + networks = ["1::1/128", "2001:db8:f::1:17/128"] + result = verify_bgp_community(tgen, "ipv6", dut, networks, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify large-community-list for static and connected ipv6 route" " on r4") + dut = "r4" + networks = ["1::1/128", "2001:db8:f::1:17/128"] + result = verify_bgp_community(tgen, "ipv6", dut, networks, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_set_delete(request): + """ + This test is to verify if we want to remove specific large-community + values from a set of prefix we can make use of DELETE operation based + on L-comm list + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("configure route_map") + input_dict_2 = { + "r6": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "Test", + "value": "1:2:1 1:1:10 1:3:100", + "large": True, + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create route map") + input_dict_3 = { + "r6": { + "route_maps": { + "RM_R6_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": {"large_comm_list": {"id": "Test", "delete": True}}, + } + ] + } + }, + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "1:2:1 1:1:10 1:3:100 2:1:1 2:2:2 2:3:3" + " 2:4:4 2:5:5", + "action": "additive", + } + }, + } + ] + } + }, + } + result = create_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_4 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + } + } + }, + "r6": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": { + "route_maps": [ + {"name": "RM_R6_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r6": { + "route_maps": [ + {"name": "RM_R6_IN", "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 large-community-list") + dut = "r6" + input_dict_5 = {"largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"} + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_no_send_community(request): + """ + This test is to verify if we want to remove specific large-community + values from a set of prefix we can make use of DELETE operation based + on L-comm list + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r5": { + "route_maps": { + "RM_R6_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": {"num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"} + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r5": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r5": { + "route_maps": [ + { + "name": "RM_R6_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r5": { + "route_maps": [ + { + "name": "RM_R6_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify large-community-list") + dut = "r6" + input_dict_4 = {"largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"} + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Configure neighbor for no-send-community") + input_dict_5 = { + "r5": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": {"r5": {"no_send_community": "large"}} + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": {"r5": {"no_send_community": "large"}} + } + } + } + }, + } + } + } + } + result = create_router_bgp(tgen, topo, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify Community-list") + for adt in ADDR_TYPES: + result = verify_bgp_community( + tgen, adt, dut, NETWORKS[adt], input_dict_4, expected=False + ) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_create_large_community_lists_with_no_attribute_values(request): + """ + This test is to verify that large-community lists can not be + configured without providing specific L-community values + (for match/delete operation in a route-map). + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create standard large commumity-list") + input_dict_1 = { + "r5": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "Test1", + "large": True, + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_1) + assert result is not True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_match_exact(request): + """ + This test is to verify that Match_EXACT clause should pass + only if all of the L-comm values configured (horizontally) + in the community list is present in the prefix. There must + be no additional L-communities in the prefix. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r2": { + "route_maps": { + "RM_R4_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": {"num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"} + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map and advertise networks") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + } + } + }, + } + + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create standard large commumity-list") + input_dict_4 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "EXACT", + "value": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5", + "large": True, + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "match": { + "large-community-list": ["EXACT"], + "match_exact": True, + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map") + input_dict_6 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "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 large-community-list") + dut = "r4" + input_dict_4 = {"largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"} + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_match_all(request): + """ + This test is to verify that Match_ALL clause should pass + only if ALL of the L-comm values configured (horizontally) + in the community list are present in the prefix. There + could be additional L-communities in the prefix that are + not present in the L-comm list. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r2": { + "route_maps": { + "RM_R4_OUT": [ + { + "action": "permit", + "set": { + "large_community": { + "num": "1:1:1 1:2:3 2:1:1 2:2:2 2:3:3 2:4:4 2:5:5" + } + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create standard large commumity-list") + input_dict_4 = { + "r3": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ALL", + "value": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5", + "large": True, + } + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "match": {"large-community-list": {"id": "ALL"}}, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map") + input_dict_6 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "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 large-community-list") + dut = "r4" + input_dict_4 = {"largeCommunity": "1:1:1 1:2:3 2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"} + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_match_any(request): + """ + This test is to verify that Match_ANY clause should pass + only if at-least any one L-comm value configured(vertically) + in large-community list, is present in prefixes. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r2": { + "route_maps": { + "RM_R4_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": {"num": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"} + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create standard large commumity-list") + input_dict_4 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "2:1:1", + "large": True, + }, + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "2:2:1", + "large": True, + }, + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "2:3:1", + "large": True, + }, + { + "community_type": "standard", + "action": "permit", + "name": "ANY", + "value": "2:4:1", + "large": True, + }, + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "match": {"large-community-list": {"id": "ANY"}}, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map") + input_dict_6 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "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 large-community-list") + dut = "r4" + input_dict_7 = {"largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"} + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_large_community_lists_with_rmap_match_regex(request): + """ + This test is to verify large-community lists" operation in a route-map + with match RegEx statements. Match clause should pass only if the + complete string of L-comm values are matched + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Don"t run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Create route map") + input_dict_2 = { + "r2": { + "route_maps": { + "RM_R4_OUT": [ + { + "action": "permit", + "seq_id": "10", + "set": { + "large_community": { + "num": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5", + }, + "community": {"num": "1:1 1:2 1:3 1:4 1:5"}, + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map") + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [{"network": "200.50.2.0/32"}] + } + }, + "ipv6": { + "unicast": {"advertise_networks": [{"network": "1::1/128"}]} + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2": { + "route_maps": [ + { + "name": "RM_R4_OUT", + "direction": "out", + } + ] + } + } + } + } + } + }, + } + } + }, + } + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create standard large commumity-list") + input_dict_4 = { + "r4": { + "bgp_community_lists": [ + { + "community_type": "standard", + "action": "permit", + "name": "ALL", + "value": "1:1:1 2:1:3 2:1:4 2:1:5", + "large": True, + }, + { + "community_type": "expanded", + "action": "permit", + "name": "EXP_ALL", + "value": "1:1:1 2:1:[3-5]", + "large": True, + }, + ] + } + } + result = create_bgp_community_lists(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify BGP large community is created") + result = verify_create_community_list(tgen, input_dict_4) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "10", + "match": { + "large_community_list": { + "id": "ALL", + }, + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Configure neighbor for route map") + input_dict_6 = { + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "direction": "in"} + ] + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4": { + "route_maps": [ + {"name": "RM_R4_IN", "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 large-community-list") + dut = "r4" + input_dict_7 = {"largeCommunity": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5"} + for adt in ADDR_TYPES: + result = verify_bgp_community(tgen, adt, dut, NETWORKS[adt], input_dict_7) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Delete route map reference by community-list") + input_dict_3 = {"r4": {"route_maps": ["RM_R4_IN"]}} + result = delete_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + result = verify_route_maps(tgen, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Create route map") + input_dict_5 = { + "r4": { + "route_maps": { + "RM_R4_IN": [ + { + "action": "permit", + "seq_id": "20", + "match": { + "large_community_list": { + "id": "EXP_ALL", + }, + }, + } + ] + } + } + } + result = create_route_maps(tgen, input_dict_5) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("clear ip bgp") + result = clear_bgp_and_verify(tgen, topo, "r4") + assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) + + step("Verify large-community-list") + dut = "r4" + input_dict_7 = {"largeCommunity": "1:1:1 1:1:2 2:1:3 2:1:4 2:1:5"} + for adt in ADDR_TYPES: + result = verify_bgp_community( + tgen, adt, dut, NETWORKS[adt], input_dict_7, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "largeCommunity is still present \n Error: {}".format(tc_name, result) + ) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) |