diff --git a/docs/testplan/routing_policies.md b/docs/testplan/routing_policies.md new file mode 100644 index 00000000000..ffe7abfa6ce --- /dev/null +++ b/docs/testplan/routing_policies.md @@ -0,0 +1,245 @@ +# Routing policies test plan + +- [Routing Policies testplan](#bgp-routing-policies-testplan) + - [Overview](#Overview) + - [Scope](#Scope) + - [Testbed](#Keysight-Testbed) + - [Topology](#Topology) + - [Test methodology](#Test-methodology) + - [Test cases](#Test-cases) + - [Test case # 1 – Peer Routing Policies](#test-case--1--peer-routing-policies) + - [Test objective](#Test-objective) + - [Test steps](#Test-steps) + - [Test results](#Test-results) + - [Test case # 2 – Community List Filtering](#test-case--2--community-list-filtering) + - [Test objective](#Test-objective-1) + - [Test steps](#Test-steps-1) + - [Test results](#Test-results-1) + - [Test case # 3 – Prefix List Filtering](#test-case--3--prefix-list-filtering) + - [Test objective](#Test-objective-2) + - [Test steps](#Test-steps-2) + - [Test results](#Test-results-2) + - [Test case # 4 – Metric Filter](#test-case--4--metric-filter) + - [Test objective](#Test-objective-3) + - [Test steps](#Test-steps-3) + - [Test results](#Test-results-3) + - [Test case # 5 – Group-As-Path Modified](#test-case--5--group-as-path-modified) + - [Test objective](#Test-objective-4) + - [Test steps](#Test-steps-4) + - [Test results](#Test-results-4) + - [Test case # 6 – Group Origin Code Modification](#test-case--6--group-origin-code-modification) + - [Test objective](#Test-objective-5) + - [Test steps](#Test-steps-5) + - [Test results](#Test-results-5) + + +## Overview +The purpose of these tests is to evaluate the BGP Routing Policies Using Match Conditions and Actions. The routing policy consists of multiple terms. Each term consists of match conditions and actions to apply to matching routes. + +### Scope +These tests are targeted on fully functioning SONiC system. The purpose of these tests are to evaluate the BGP Routing Policies Using Match Conditions and Actions. + +### Keysight Testbed +The tests will run on following testbeds: +* t0 + +![Single DUT Topology ](Img/Single_DUT_Topology.png) + +## Topology + +``` + _________ + | | +IXIA TGEN1 -------- | DUT |------ IXIA TGEN2 + |_________| +``` + +## Test Methodology +Following test methodology will be used to evaluate routing policies. +* Traffic generator will be used to configure ebgp peering between TGEN1 and SONiC DUT by advertising IPv4/IPv6, dual-stack routes. +* Advertise 2 IPv4 and 2 IPv6 routes from TGEN1. +* Create four flows from TGEN2 to TGEN1 + 1. `permit` -- TGEN2 to TGEN1("200.1.0.0") + 2. `permit_ipv6` -- TGEN2 to TGEN1("4000::1") + 3. `deny` -- TGEN2 to TGEN1("20.1.0.0") + 4. `deny_ipv6` -- TGEN2 to TGEN1("6000::1") +* update the BGP attributes as per route policy for route in `permit` & `permit_ipv6` +and validate the actions applied to match routes. + + +## Test cases +### Test case # 1 – Peer Routing Policies +#### Test objective +Routing policy in the DUT match conditions with BGP attributes (community, as-path, metric, origin) and permit the routes. + + +#### Test steps +1. Configure BGP between DUT and TGEN1. +2. Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 via BGP. + + 1. "200.1.0.0" & "4000::1" with Attributes + a) community-list 1:2 + b) as-path append AS 100 + c) Origin ebgp + d) Metric 50 + 2. "20.1.0.0" & "6000::1" without Attributes +3. Create route-map in DUT to permit only `200.1.0.0` + & `4000::1` based on BGP Attributes +4. Create four flows from TGEN2 to TGEN1 + + 1) permit -- TGEN2 to TGEN1("200.1.0.0") + 2) permit_ipv6 -- TGEN2 to TGEN1("4000::1") + 3) deny -- TGEN2 to TGEN1("20.1.0.0") + 4) deny_ipv6 -- TGEN2 to TGEN1("6000::1") + +#### Test results +1. Send traffic without applying route-map + + Result: Should not observe traffic loss in the flows 'permit','deny','permit_ipv6' & 'deny_ipv6' +2. Apply route-map + + Result: Should observe 100% traffic loss in the flows 'deny' & 'deny_ipv6' + + +### Test case # 2 – Community List Filtering +#### Test objective +Routing policy in the DUT match conditions with BGP Community and permit the routes with Community. + + +#### Test steps +1. Configure BGP between DUT and TGEN1. +2. Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 via BGP. + + 1. "200.1.0.0" & "4000::1" with Community List + 2. "20.1.0.0" & "6000::1" without Community List +3. Create route-map in DUT to permit only `200.1.0.0` + & `4000::1` based on BGP Community List +4. Create four flows from TGEN2 to TGEN1 + + 1) permit -- TGEN2 to TGEN1("200.1.0.0") + 2) permit_ipv6 -- TGEN2 to TGEN1("4000::1") + 3) deny -- TGEN2 to TGEN1("20.1.0.0") + 4) deny_ipv6 -- TGEN2 to TGEN1("6000::1") + +#### Test results +1. Send traffic without applying route-map + + Result: Should not observe traffic loss in the flows 'permit', 'deny', 'permit_ipv6' & 'deny_ipv6' +2. Apply route-map + + Result: Should observe 100% traffic loss in the flows 'deny' & 'deny_ipv6' + +### Test case # 3 – Prefix List Filtering +#### Test objective +Routing policy in the DUT match conditions with Prefix-list and permit based on Prefix List Filtering. + + +#### Test steps +1. Configure BGP between DUT and TGEN1. +2. Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 via BGP. + + 1. "200.1.0.0" & "4000::1" + 2. "20.1.0.0" & "6000::1" +3. Create Prefix-list route-map in DUT to permit only `200.1.0.0` + & `4000::1` +4. Create four flows from TGEN2 to TGEN1 + + 1) permit -- TGEN2 to TGEN1("200.1.0.0") + 2) permit_ipv6 -- TGEN2 to TGEN1("4000::1") + 3) deny -- TGEN2 to TGEN1("20.1.0.0") + 4) deny_ipv6 -- TGEN2 to TGEN1("6000::1") + +#### Test results +1. Send traffic without applying route-map + + Result: Should not observe traffic loss in the flows 'permit','deny','permit_ipv6' & 'deny_ipv6' +2. Apply route-map + + Result: Should observe 100% traffic loss in the flows 'deny' & 'deny_ipv6' + + +### Test case # 4 – Metric Filter +#### Test objective +Routing policy in the DUT match conditions with Metric and permit based on Metric Filtering. + + +#### Test steps +1. Configure BGP between DUT and TGEN1. +2. Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 via BGP. + + 1."200.1.0.0" & "4000::1" with Metric 50 + 2."20.1.0.0" & "6000::1" with default Metric +3. Create route-map in DUT to permit only `200.1.0.0` + & `4000::1` with Metric 50 +4. Create four flows from TGEN2 to TGEN1 + + 1) permit -- TGEN2 to TGEN1("200.1.0.0") + 2) permit_ipv6 -- TGEN2 to TGEN1("4000::1") + 3) deny -- TGEN2 to TGEN1("20.1.0.0") + 4) deny_ipv6 -- TGEN2 to TGEN1("6000::1") + +#### Test results +1. Send traffic without applying route-map + + Result: Should not observe traffic loss in the flows 'permit','deny','permit_ipv6' & 'deny_ipv6' +2. Apply route-map + + Result: Should observe 100% traffic loss in the flows 'deny' & 'deny_ipv6' + + +### Test case # 5 – Group-As-Path Modified +#### Test objective +Routing policy in the DUT match conditions with group-as-path and permit based on group-as-path Modification. + + +#### Test steps +1. Configure BGP between DUT and TGEN1. +2. Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 via BGP. + + 1."200.1.0.0" & "4000::1" with group AS 100 + 2."20.1.0.0" & "6000::1" without group AS 100 +3. Create route-map in DUT to permit only `200.1.0.0` + & `4000::1` with group AS 100 +4. Create four flows from TGEN2 to TGEN1 + + 1) permit -- TGEN2 to TGEN1("200.1.0.0") + 2) permit_ipv6 -- TGEN2 to TGEN1("4000::1") + 3) deny -- TGEN2 to TGEN1("20.1.0.0") + 4) deny_ipv6 -- TGEN2 to TGEN1("6000::1") + +#### Test results +1. Send traffic without applying route-map + + Result: Should not observe traffic loss in the flows 'permit','deny','permit_ipv6' & 'deny_ipv6' +2. Apply route-map + + Result: Should observe 100% traffic loss in the flows 'deny' & 'deny_ipv6' + + +### Test case # 6 – Group Origin Code Modification +#### Test objective +Routing policy in the DUT match conditions with Origin and permit based on Origin + + +#### Test steps +1. Configure BGP between DUT and TGEN1. +2. Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 via BGP. + + 1."200.1.0.0" & "4000::1" with Origin 'egp' + 2."20.1.0.0" & "6000::1" +3. Create route-map in DUT to permit only `200.1.0.0` + & `4000::1` with Origin 'egp' +4. Create four flows from TGEN2 to TGEN1 + + 1) permit -- TGEN2 to TGEN1("200.1.0.0") + 2) permit_ipv6 -- TGEN2 to TGEN1("4000::1") + 3) deny -- TGEN2 to TGEN1("20.1.0.0") + 4) deny_ipv6 -- TGEN2 to TGEN1("6000::1") + +#### Test results +1. Send traffic without applying route-map + + Result: Should not observe traffic loss in the flows 'permit','deny','permit_ipv6' & 'deny_ipv6' +2. Apply route-map + + Result: Should observe 100% traffic loss in the flows 'deny' & 'deny_ipv6' diff --git a/tests/common/ixia/common_helpers.py b/tests/common/ixia/common_helpers.py index b38d4beb9cb..a2a2e5e017d 100644 --- a/tests/common/ixia/common_helpers.py +++ b/tests/common/ixia/common_helpers.py @@ -13,6 +13,8 @@ import ipaddr from netaddr import IPNetwork +from ipaddress import IPv6Network, IPv6Address +from random import getrandbits from tests.common.mellanox_data import is_mellanox_device as isMellanoxDevice def increment_ip_address (ip, incr=1) : @@ -119,6 +121,32 @@ def get_addrs_in_subnet(subnet, number_of_ip): return ip_addrs[:number_of_ip] + +def get_ipv6_addrs_in_subnet(subnet, number_of_ip): + """ + Get N IPv6 addresses in a subnet. + + Args: + subnet (str): IPv6 subnet, e.g., '2001::1/64' + number_of_ip (int): Number of IP addresses to get + + Return: + Return n IPv6 addresses in this subnet in a list. + """ + + subnet = str(IPNetwork(subnet).network) + "/" + str(subnet.split("/")[1]) + subnet = unicode(subnet, "utf-8") + ipv6_list = [] + for i in range(number_of_ip): + network = IPv6Network(subnet) + address = IPv6Address( + network.network_address + getrandbits( + network.max_prefixlen - network.prefixlen)) + ipv6_list.append(str(address)) + + return ipv6_list + + def get_peer_ixia_chassis(conn_data, dut_hostname): """ Get the IXIA chassis connected to the DUT diff --git a/tests/common/ixia/ixia_fixtures.py b/tests/common/ixia/ixia_fixtures.py index 5b04c2f7783..91cca96d01e 100644 --- a/tests/common/ixia/ixia_fixtures.py +++ b/tests/common/ixia/ixia_fixtures.py @@ -9,8 +9,9 @@ from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\ fanout_graph_facts from tests.common.ixia.common_helpers import get_vlan_subnet, get_addrs_in_subnet,\ - get_peer_ixia_chassis + get_peer_ixia_chassis, get_ipv6_addrs_in_subnet from tests.common.ixia.ixia_helpers import IxiaFanoutManager, get_tgen_location +import snappi try: from abstract_open_traffic_generator.port import Port @@ -294,3 +295,111 @@ def ixia_testbed(conn_graph_facts, config.devices.append(device) return config + + +@pytest.fixture(scope='module') +def snappi_api(ixia_api_serv_ip, + ixia_api_serv_port): + """ + Snappi session fixture for snappi Tgen API + + Args: + ixia_api_serv_ip (pytest fixture): ixia_api_serv_ip fixture + ixia_api_serv_port (pytest fixture): ixia_api_serv_port fixture. + """ + host = "https://" + ixia_api_serv_ip + ":" + str(ixia_api_serv_port) + api = snappi.api(host=host, ext="ixnetwork") + + yield api + + if api.assistant is not None: + api.assistant.Session.remove() + + +@pytest.fixture(scope="module") +def tgen_ports(duthost, + conn_graph_facts, + fanout_graph_facts): + + """ + Populate tgen ports info of T0 testbed and returns as a list + + Args: + duthost (pytest fixture): duthost fixture + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + + Return: + [{'card_id': '1', + 'ip': '22.1.1.2', + 'ipv6': '3001::2', + 'ipv6_prefix': u'64', + 'location': '10.36.78.238;1;2', + 'peer_device': 'sonic-s6100-dut', + 'peer_ip': u'22.1.1.1', + 'peer_ipv6': u'3001::1', + 'peer_port': 'Ethernet8', + 'port_id': '2', + 'prefix': u'24', + 'speed': 'speed_400_gbps'}, + {'card_id': '1', + 'ip': '21.1.1.2', + 'ipv6': '2001::2', + 'ipv6_prefix': u'64', + 'location': '10.36.78.238;1;1', + 'peer_device': 'sonic-s6100-dut', + 'peer_ip': u'21.1.1.1', + 'peer_ipv6': u'2001::1', + 'peer_port': 'Ethernet0', + 'port_id': '1', + 'prefix': u'24', + 'speed': 'speed_400_gbps'}] + """ + + speed_type = {'50000': 'speed_50_gbps', + '100000': 'speed_100_gbps', + '200000': 'speed_200_gbps', + '400000': 'speed_400_gbps'} + + ixia_fanout = get_peer_ixia_chassis(conn_data=conn_graph_facts, + dut_hostname=duthost.hostname) + ixia_fanout_id = list(fanout_graph_facts.keys()).index(ixia_fanout) + ixia_fanout_list = IxiaFanoutManager(fanout_graph_facts) + ixia_fanout_list.get_fanout_device_details(device_number=ixia_fanout_id) + ixia_ports = ixia_fanout_list.get_ports(peer_device=duthost.hostname) + port_speed = None + + for i in range(len(ixia_ports)): + if port_speed is None: + port_speed = int(ixia_ports[i]['speed']) + + elif port_speed != int(ixia_ports[i]['speed']): + """ All the ports should have the same bandwidth """ + return None + + config_facts = duthost.config_facts(host=duthost.hostname, + source="running")['ansible_facts'] + + for port in ixia_ports: + port['location'] = get_tgen_location(port) + port['speed'] = speed_type[port['speed']] + + for port in ixia_ports: + + peer_port = port['peer_port'] + int_addrs = config_facts['INTERFACE'][peer_port].keys() + ipv4_subnet = [ele for ele in int_addrs if "." in ele][0] + ipv6_subnet = [ele for ele in int_addrs if ":" in ele][0] + if not ipv4_subnet: + raise Exception("IPv4 is not configured on the interface {}" + .format(peer_port)) + port['peer_ip'], port['prefix'] = ipv4_subnet.split("/") + port['ip'] = get_addrs_in_subnet(ipv4_subnet, 1)[0] + + if not ipv6_subnet: + raise Exception("IPv6 is not configured on the interface {}" + .format(peer_port)) + port['peer_ipv6'], port['ipv6_prefix'] = ipv6_subnet.split("/") + port['ipv6'] = get_ipv6_addrs_in_subnet(ipv6_subnet, 1)[0] + + return ixia_ports diff --git a/tests/ixia/bgp/files/__init__.py b/tests/ixia/bgp/files/__init__.py new file mode 100644 index 00000000000..65d74fc0a6b --- /dev/null +++ b/tests/ixia/bgp/files/__init__.py @@ -0,0 +1 @@ +# Local library for BGP tests. \ No newline at end of file diff --git a/tests/ixia/bgp/files/helper.py b/tests/ixia/bgp/files/helper.py new file mode 100644 index 00000000000..d80a0d87e9c --- /dev/null +++ b/tests/ixia/bgp/files/helper.py @@ -0,0 +1,1033 @@ +from tests.common.helpers.assertions import pytest_assert +from tests.common.utilities import wait_until +import logging + +logger = logging.getLogger(__name__) + +DUT_AS_NUM = 10086 +TGEN_AS_NUM = 501 +BGP_TYPE = 'ebgp' +PACKETS = 100000 +LINE_RATE = 1 +COMMUNITY = "1:2" +MED = 50 +GROUP_AS = [100] + + +def config_setup(duthost, + tgen_ports): + """ + BGP Config on duthost + + Args: + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + """ + logger.info("|--Remove Any Existing BGP Process on DUT--|") + try: + duthost.shell( + "vtysh " + "-c 'configure terminal' " + "-c 'no router bgp' " + ) + except Exception: + logger.info("No BGP process is configured") + + logger.info("|--Interface Configuration On DUT--|") + intf1_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'interface %s' " + "-c 'ip address %s/%s' " + ) + intf1_config %= (tgen_ports[0]['peer_port'], + tgen_ports[0]['peer_ip'], + tgen_ports[0]['prefix']) + duthost.shell(intf1_config) + + intf2_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'interface %s' " + "-c 'ip address %s/%s' " + ) + intf2_config %= (tgen_ports[1]['peer_port'], + tgen_ports[1]['peer_ip'], + tgen_ports[1]['prefix']) + duthost.shell(intf2_config) + + # ipv6 interface config + intf1_v6_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'interface %s' " + "-c 'ipv6 address %s/%s' " + ) + intf1_v6_config %= (tgen_ports[0]['peer_port'], + tgen_ports[0]['peer_ipv6'], + tgen_ports[0]['ipv6_prefix']) + duthost.shell(intf1_v6_config) + + intf2_v6_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'interface %s' " + "-c 'ipv6 address %s/%s' " + ) + intf2_v6_config %= (tgen_ports[1]['peer_port'], + tgen_ports[1]['peer_ipv6'], + tgen_ports[1]['ipv6_prefix']) + duthost.shell(intf2_v6_config) + + logger.info("|--BGP Configuration On DUT--|") + bgp_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'no bgp default ipv4-unicast' " + "-c 'no bgp ebgp-requires-policy' " + "-c 'neighbor LC peer-group' " + "-c 'neighbor LC remote-as %s' " + "-c 'neighbor %s peer-group LC' " + "-c 'address-family ipv4 unicast' " + "-c 'neighbor %s activate' " + ) + bgp_config %= (DUT_AS_NUM, + TGEN_AS_NUM, + tgen_ports[0]['ip'], + tgen_ports[0]['ip']) + duthost.shell(bgp_config) + + bgpv6_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'neighbor LCv6 peer-group' " + "-c 'neighbor LCv6 remote-as %s' " + "-c 'neighbor %s peer-group LCv6' " + "-c 'address-family ipv6 unicast' " + "-c 'neighbor %s activate' " + ) + bgpv6_config %= (DUT_AS_NUM, + TGEN_AS_NUM, + tgen_ports[0]['ipv6'], + tgen_ports[0]['ipv6']) + duthost.shell(bgpv6_config) + + # ipv6 next hop route-map + next_hop = ( + "vtysh " + "-c 'configure terminal' " + "-c 'route-map NEXTHOP permit 1' " + "-c 'on-match next' " + "-c 'set ipv6 next-hop prefer-global' " + "-c 'router bgp %s' " + "-c 'address-family ipv6 unicast' " + "-c 'neighbor LCv6 route-map NEXTHOP in' " + ) + next_hop %= (DUT_AS_NUM) + duthost.shell(next_hop) + + +def run_peer_routing_policies_test(snappi_api, + duthost, + tgen_ports): + """ + Run BGP Peer Routing Policies Test + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + """ + logger.info("|--Create BGP TGEN Configuration--|") + tgen_bgp_config = __tgen_bgp_config(snappi_api, + tgen_ports) + + logger.info("|--Updating TGEN Config with BGP Route Attributes--|") + tgen_policies_config = __tgen_policies_config(tgen_bgp_config) + + logger.info("|--BGP Policy Route Map Configuration on DUT--|") + __policies_route_map_config(duthost) + + logger.info("|--Verify Test--|") + __verify_test(duthost, + snappi_api, + tgen_policies_config) + + +def run_community_list_filtering_test(snappi_api, + duthost, + tgen_ports): + """ + Run BGP Community List Filtering Test + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + """ + logger.info("|--Create BGP TGEN Configuration--|") + tgen_bgp_config = __tgen_bgp_config(snappi_api, + tgen_ports) + + logger.info("|--Updating TGEN Config with BGP Community Attribute--|") + tgen_community_config = __tgen_community_config(tgen_bgp_config) + + logger.info("|--BGP Community Route Map Configuration on DUT--|") + __community_route_map_config(duthost) + + logger.info("|--Verify Test--|") + __verify_test(duthost, + snappi_api, + tgen_community_config) + + +def run_prefix_list_filtering_test(snappi_api, + duthost, + tgen_ports): + """ + Run BGP Prefix List Filtering Test + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + """ + logger.info("|--Create BGP TGEN Configuration--|") + tgen_bgp_config = __tgen_bgp_config(snappi_api, + tgen_ports) + + logger.info("|--BGP Prefix List Route Map Configuration on DUT--|") + __prefix_list_route_map_config(duthost) + + logger.info("|--Verify Test--|") + __verify_test(duthost, + snappi_api, + tgen_bgp_config) + + +def run_test_metric_filter(snappi_api, + duthost, + tgen_ports): + """ + Run BGP Metric Filter Test + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + """ + + logger.info("|--Create BGP TGEN Configuration--|") + tgen_bgp_config = __tgen_bgp_config(snappi_api, + tgen_ports) + + logger.info("|--Updating TGEN Config with Metric/MED Attribute--|") + tgen_metric_config = __tgen_metric_config(tgen_bgp_config) + + logger.info("|--BGP Metric Route Map Configuration on DUT--|") + __metric_route_map_config(duthost) + + logger.info("|--Verify Test--|") + __verify_test(duthost, + snappi_api, + tgen_metric_config) + + +def run_group_as_path_modified(snappi_api, + duthost, + tgen_ports): + """ + Run BGP group-as-path Modified Test + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + """ + logger.info("|--Create BGP TGEN Configuration--|") + tgen_bgp_config = __tgen_bgp_config(snappi_api, + tgen_ports) + + logger.info("|--Updating TGEN Config with Group AS-PATH Attribute--|") + tgen_as_path_modified_config = __tgen_as_path_modified_config( + tgen_bgp_config) + + logger.info("|--BGP AS-PATH Route Map Configuration on DUT--|") + __as_path_route_map_config(duthost) + + logger.info("|--Verify Test--|") + __verify_test(duthost, + snappi_api, + tgen_as_path_modified_config) + + +def run_origin_code_modification(snappi_api, + duthost, + tgen_ports): + """ + Run BGP Origin Code Modification Test + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + """ + logger.info("|--Create BGP TGEN Configuration--|") + tgen_bgp_config = __tgen_bgp_config(snappi_api, + tgen_ports) + + logger.info("|--Updating TGEN Config with Origin Attribute--|") + tgen_origin_config = __tgen_origin_config(tgen_bgp_config) + + logger.info("|--BGP Origin Route Map Configuration on DUT--|") + __origin_route_map_config(duthost) + + logger.info("|--Verify Test--|") + __verify_test(duthost, + snappi_api, + tgen_origin_config) + + +# Common TGEN BGP Config +def __tgen_bgp_config(snappi_api, + tgen_ports): + """ + BGP Config on TGEN + Args: + snappi_api (pytest fixture): Snappi API + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + """ + config = snappi_api.config() + + tgen1, tgen2 = ( + config.ports + .port(name='tgen1', location=tgen_ports[0]['location']) + .port(name='tgen2', location=tgen_ports[1]['location']) + ) + + # L1 Config + config.options.port_options.location_preemption = True + ly = config.layer1.layer1()[-1] + ly.name = 'ly' + ly.port_names = [tgen1.name, tgen2.name] + ly.speed = tgen_ports[0]['speed'] + ly.auto_negotiate = False + + # Device Config + d1, d2 = config.devices.device(name='d1').device(name='d2') + d1.container_name = tgen1.name + d2.container_name = tgen2.name + + eth1, eth2 = d1.ethernet, d2.ethernet + eth1.name, eth2.name = "eth1", "eth2" + + ip1, ip2 = eth1.ipv4, eth2.ipv4 + ip1.name, ip2.name = "ip1", "ip2" + + ip1.address = tgen_ports[0]['ip'] + ip1.gateway = tgen_ports[0]['peer_ip'] + ip1.prefix = tgen_ports[0]['prefix'] + + ip2.address = tgen_ports[1]['ip'] + ip2.gateway = tgen_ports[1]['peer_ip'] + ip2.prefix = tgen_ports[1]['prefix'] + + # BGPv4 + bgp = ip1.bgpv4 + bgp.name = "bgp" + bgp.dut_address = tgen_ports[0]['peer_ip'] + bgp.as_number = TGEN_AS_NUM + bgp.as_type = BGP_TYPE + + # v6 config + ip1v6, ip2v6 = eth1.ipv6, eth2.ipv6 + ip1v6.name, ip2v6.name = "ip1v6", "ip2v6" + + ip1v6.address = tgen_ports[0]['ipv6'] + ip1v6.gateway = tgen_ports[0]['peer_ipv6'] + ip1v6.prefix = tgen_ports[0]['ipv6_prefix'] + + ip2v6.address = tgen_ports[1]['ipv6'] + ip2v6.gateway = tgen_ports[1]['peer_ipv6'] + ip2v6.prefix = tgen_ports[1]['ipv6_prefix'] + + # BGPv6 + bgpv6 = ip1v6.bgpv6 + bgpv6.name = "bgpv6" + bgpv6.dut_address = tgen_ports[0]['peer_ipv6'] + bgpv6.as_number = TGEN_AS_NUM + bgpv6.as_type = BGP_TYPE + + # Routes Config + bgp_route1, bgp_route2 = ( + bgp.bgpv4_routes + .bgpv4route(name="bgp_route1") + .bgpv4route(name="bgp_route2") + ) + + # Advertise one route("200.1.0.0") + bgp_route1.addresses.bgpv4routeaddress(address="200.1.0.0", + prefix=16) + + # Advertise another route("20.1.0.0") + bgp_route2.addresses.bgpv4routeaddress(address="20.1.0.0", + prefix=16) + + # Routes Config + bgpv6_route1, bgpv6_route2 = ( + bgpv6.bgpv6_routes + .bgpv6route(name="bgpv6_route1") + .bgpv6route(name="bgpv6_route2") + ) + + # Advertise one route("4000::1") with Attributes + bgpv6_route1.addresses.bgpv6routeaddress(address="4000::1", + prefix=64) + + # Advertise another route("6000::1") + bgpv6_route2.addresses.bgpv6routeaddress(address="6000::1", + prefix=64) + + # Create four flows + permit, deny, permit_ipv6, deny_ipv6 = ( + config.flows + .flow(name='permit') + .flow(name='deny') + .flow(name='permit_ipv6') + .flow(name='deny_ipv6') + ) + + permit.tx_rx.device.tx_names = [ip2.name] + permit.tx_rx.device.rx_names = [bgp_route1.name] + + deny.tx_rx.device.tx_names = [ip2.name] + deny.tx_rx.device.rx_names = [bgp_route2.name] + + permit.rate.percentage = LINE_RATE + permit.duration.fixed_packets.packets = PACKETS + + deny.rate.percentage = LINE_RATE + deny.duration.fixed_packets.packets = PACKETS + + permit_ipv6.tx_rx.device.tx_names = [ip2v6.name] + permit_ipv6.tx_rx.device.rx_names = [bgpv6_route1.name] + + deny_ipv6.tx_rx.device.tx_names = [ip2v6.name] + deny_ipv6.tx_rx.device.rx_names = [bgpv6_route2.name] + + permit_ipv6.rate.percentage = LINE_RATE + permit_ipv6.duration.fixed_packets.packets = PACKETS + + deny_ipv6.rate.percentage = LINE_RATE + deny_ipv6.duration.fixed_packets.packets = PACKETS + + return config + + +def __tgen_policies_config(config): + """ + BGP Attributes Config on TGEN + Args: + config : tgen config + """ + + # update route("200.1.0.0") with attributes + bgp_route_with_policies = ( + config.devices[0].ethernet.ipv4.bgpv4.bgpv4_routes[0]) + + # Community + manual_as_community = ( + bgp_route_with_policies.communities.bgpcommunity()[-1]) + manual_as_community.community_type = manual_as_community.MANUAL_AS_NUMBER + manual_as_community.as_number = int(COMMUNITY.split(":")[0]) + manual_as_community.as_custom = int(COMMUNITY.split(":")[1]) + # Metric + bgp_route_with_policies.advanced.multi_exit_discriminator = MED + # AS PATH + as_path = bgp_route_with_policies.as_path + as_path_segment = as_path.as_path_segments.bgpaspathsegment()[-1] + as_path_segment.segment_type = as_path_segment.AS_SEQ + as_path_segment.as_numbers = GROUP_AS + # Origin + bgp_route_with_policies.advanced.origin = ( + bgp_route_with_policies.advanced.EGP) + + # update route("4000::1") with attributes + bgpv6_route_with_policies = ( + config.devices[0].ethernet.ipv6.bgpv6.bgpv6_routes[0]) + + # Community + manual_as_community = ( + bgpv6_route_with_policies.communities.bgpcommunity()[-1]) + manual_as_community.community_type = manual_as_community.MANUAL_AS_NUMBER + manual_as_community.as_number = int(COMMUNITY.split(":")[0]) + manual_as_community.as_custom = int(COMMUNITY.split(":")[1]) + # Metric + bgpv6_route_with_policies.advanced.multi_exit_discriminator = MED + # AS PATH + as_path = bgpv6_route_with_policies.as_path + as_path_segment = as_path.as_path_segments.bgpaspathsegment()[-1] + as_path_segment.segment_type = as_path_segment.AS_SEQ + as_path_segment.as_numbers = GROUP_AS + # Origin + bgpv6_route_with_policies.advanced.origin = ( + bgpv6_route_with_policies.advanced.EGP) + + return config + + +def __policies_route_map_config(duthost): + """ + BGP Policy Route MAP Config on duthost + Args: + duthost : duthost fixture + """ + # Remove route_map if exists already + duthost.shell( + "vtysh " + "-c 'configure terminal' " + "-c 'no route-map LA' " + "-c 'no route-map LAv6' " + ) + + as_path_access_list = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no bgp as-path access-list PERMIT_100' " + ) + try: + duthost.shell(as_path_access_list) + except Exception: + pass + + community = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no bgp community-list 10' " + ) + try: + duthost.shell(community) + except Exception: + pass + + # Configure route_map + policy_route_map_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'bgp community-list 10 permit 1:2' " + "-c 'bgp as-path access-list PERMIT_100 permit 100' " + "-c 'route-map LA permit 30' " + "-c 'match community 10' " + "-c 'match as-path PERMIT_100' " + "-c 'match metric 50' " + "-c 'match origin egp' " + "-c 'route-map LAv6 permit 30' " + "-c 'match community 10' " + "-c 'match as-path PERMIT_100' " + "-c 'match metric 50' " + "-c 'match origin egp' " + ) + duthost.shell(policy_route_map_config) + + +def __tgen_community_config(config): + """ + BGP Community Config on TGEN + Args: + config : tgen config + """ + + # update route("200.1.0.0") with community 1:2 + bgp_route_with_community = ( + config.devices[0].ethernet.ipv4.bgpv4.bgpv4_routes[0]) + + manual_as_community = ( + bgp_route_with_community.communities.bgpcommunity()[-1]) + manual_as_community.community_type = manual_as_community.MANUAL_AS_NUMBER + manual_as_community.as_number = int(COMMUNITY.split(":")[0]) + manual_as_community.as_custom = int(COMMUNITY.split(":")[1]) + + # update route("4000::1") with community 1:2 + bgpv6_route_with_community = ( + config.devices[0].ethernet.ipv6.bgpv6.bgpv6_routes[0]) + + manual_as_community = ( + bgpv6_route_with_community.communities.bgpcommunity()[-1]) + manual_as_community.community_type = manual_as_community.MANUAL_AS_NUMBER + manual_as_community.as_number = int(COMMUNITY.split(":")[0]) + manual_as_community.as_custom = int(COMMUNITY.split(":")[1]) + + return config + + +def __community_route_map_config(duthost): + """ + BGP Community Route MAP Config on duthost + Args: + duthost : duthost fixture + """ + # Remove route_map if exists already + remove_route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'address-family ipv4 unicast' " + "-c 'no neighbor LC route-map LA in' " + "-c 'address-family ipv6 unicast' " + "-c 'no neighbor LCv6 route-map LAv6 in' " + "-c 'neighbor LCv6 route-map NEXTHOP in' " + "-c 'no route-map LA' " + "-c 'no route-map LAv6' " + ) + remove_route_map %= (DUT_AS_NUM) + duthost.shell(remove_route_map) + + community = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no bgp community-list 10' " + ) + try: + duthost.shell(community) + except Exception: + pass + + # Configure route_map + community_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'bgp community-list 10 permit 1:2' " + "-c 'route-map LA permit 30' " + "-c 'match community 10' " + "-c 'route-map LAv6 permit 30' " + "-c 'match community 10' " + ) + duthost.shell(community_config) + + +def __prefix_list_route_map_config(duthost): + """ + BGP Prefix List Route MAP Config on duthost + Args: + duthost : duthost fixture + """ + + # Remove route_map if exists already + remove_route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'address-family ipv4 unicast' " + "-c 'no neighbor LC route-map LA in' " + "-c 'address-family ipv6 unicast' " + "-c 'no neighbor LCv6 route-map LAv6 in' " + "-c 'neighbor LCv6 route-map NEXTHOP in' " + "-c 'no route-map LA' " + "-c 'no route-map LAv6' " + ) + remove_route_map %= (DUT_AS_NUM) + duthost.shell(remove_route_map) + + # Configure route_map + prefix_list_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no ip prefix-list PERMIT_IP' " + "-c 'no ipv6 prefix-list PERMIT_IPV6' " + "-c 'ip prefix-list PERMIT_IP permit 200.1.0.0/16' " + "-c 'ipv6 prefix-list PERMIT_IPV6 permit 4000::1/64' " + "-c 'route-map LA permit 30' " + "-c 'match ip address prefix-list PERMIT_IP' " + "-c 'route-map LAv6 permit 30' " + "-c 'match ipv6 address prefix-list PERMIT_IPV6' " + ) + duthost.shell(prefix_list_config) + + +def __tgen_metric_config(config): + """ + BGP Metric config on TGEN + Args: + config : tgen config + """ + + # update route("200.1.0.0") with metric/MED 100 + bgp_route_metric_100 = ( + config.devices[0].ethernet.ipv4.bgpv4.bgpv4_routes[0]) + bgp_route_metric_100.advanced.multi_exit_discriminator = MED + + # update route("4000::1") with metric/MED 100 + bgpv6_route_metric_100 = ( + config.devices[0].ethernet.ipv6.bgpv6.bgpv6_routes[0]) + bgpv6_route_metric_100.advanced.multi_exit_discriminator = MED + + return config + + +def __metric_route_map_config(duthost): + """ + BGP Metric Route MAP Config on duthost + Args: + duthost : duthost fixture + """ + # Remove route_map if exists already + remove_route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'address-family ipv4 unicast' " + "-c 'no neighbor LC route-map LA in' " + "-c 'address-family ipv6 unicast' " + "-c 'no neighbor LCv6 route-map LAv6 in' " + "-c 'neighbor LCv6 route-map NEXTHOP in' " + "-c 'no route-map LA' " + "-c 'no route-map LAv6' " + ) + remove_route_map %= (DUT_AS_NUM) + duthost.shell(remove_route_map) + + # Configure route_map + metric_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'route-map LA permit 30' " + "-c 'match metric 50' " + "-c 'route-map LAv6 permit 30' " + "-c 'match metric 50' " + ) + duthost.shell(metric_config) + + +def __tgen_as_path_modified_config(config): + """ + BGP group AS config on duthost and TGEN + Args: + config : tgen config + """ + + # update route("200.1.0.0") with additional AS 100 + bgp_route_with_as_100 = ( + config.devices[0].ethernet.ipv4.bgpv4.bgpv4_routes[0]) + + as_path = bgp_route_with_as_100.as_path + as_path_segment = as_path.as_path_segments.bgpaspathsegment()[-1] + as_path_segment.segment_type = as_path_segment.AS_SEQ + as_path_segment.as_numbers = GROUP_AS + + # update route("4000::1") with additional AS 100 + bgpv6_route_with_as_100 = ( + config.devices[0].ethernet.ipv6.bgpv6.bgpv6_routes[0]) + + as_path = bgpv6_route_with_as_100.as_path + as_path_segment = as_path.as_path_segments.bgpaspathsegment()[-1] + as_path_segment.segment_type = as_path_segment.AS_SEQ + as_path_segment.as_numbers = GROUP_AS + + return config + + +def __as_path_route_map_config(duthost): + """ + BGP AS PATH Route MAP Config on duthost + Args: + duthost : duthost fixture + """ + # Remove route_map if exists already + remove_route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'address-family ipv4 unicast' " + "-c 'no neighbor LC route-map LA in' " + "-c 'address-family ipv6 unicast' " + "-c 'no neighbor LCv6 route-map LAv6 in' " + "-c 'neighbor LCv6 route-map NEXTHOP in' " + "-c 'no route-map LA' " + "-c 'no route-map LAv6' " + ) + remove_route_map %= (DUT_AS_NUM) + duthost.shell(remove_route_map) + + remove_as_path = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no bgp as-path access-list PERMIT_100' " + ) + try: + duthost.shell(remove_as_path) + except Exception: + pass + + # Configure route_map + as_path_route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'bgp as-path access-list PERMIT_100 permit 100' " + "-c 'route-map LA permit 30' " + "-c 'match as-path PERMIT_100' " + "-c 'route-map LAv6 permit 30' " + "-c 'match as-path PERMIT_100' " + ) + duthost.shell(as_path_route_map) + + +def __tgen_origin_config(config): + """ + BGP Origin config on TGEN + Args: + config : tgen config + """ + + # update route("200.1.0.0") with ORIGIN EGP + bgp_route_origin_egp = ( + config.devices[0].ethernet.ipv4.bgpv4.bgpv4_routes[0]) + + bgp_route_origin_egp.advanced.origin = bgp_route_origin_egp.advanced.EGP + + # update route("4000::1") with with ORIGIN EGP + bgpv6_route_origin_egp = ( + config.devices[0].ethernet.ipv6.bgpv6.bgpv6_routes[0]) + + bgpv6_route_origin_egp.advanced.origin = ( + bgpv6_route_origin_egp.advanced.EGP) + + return config + + +def __origin_route_map_config(duthost): + """ + BGP Origin Route MAP Config on duthost + Args: + duthost : duthost fixture + """ + + # Remove route_map if exists already + remove_route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'address-family ipv4 unicast' " + "-c 'no neighbor LC route-map LA in' " + "-c 'address-family ipv6 unicast' " + "-c 'no neighbor LCv6 route-map LAv6 in' " + "-c 'neighbor LCv6 route-map NEXTHOP in' " + "-c 'no route-map LA' " + "-c 'no route-map LAv6' " + ) + remove_route_map %= (DUT_AS_NUM) + duthost.shell(remove_route_map) + + # Configure route_map + origin_route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'route-map LA permit 30' " + "-c 'match origin egp' " + "-c 'route-map LAv6 permit 30' " + "-c 'match origin egp' " + ) + duthost.shell(origin_route_map) + + +def __verify_test(duthost, + snappi_api, + config): + """ + Test Verification + + Args: + duthost (pytest fixture): duthost fixture + snappi_api (pytest fixture): Snappi API + config: tgen_config + """ + logger.info("|--Apply TGEN Config--|") + snappi_api.set_config(config) + + # Start traffic + logger.info("|--Start Traffic--|") + ts = snappi_api.transmit_state() + ts.state = ts.START + snappi_api.set_transmit_state(ts) + + # Check there is no loss for 'permit', 'permit_ipv6', 'deny' & deny_ipv6 + logger.info( + "|--Asserting No Loss For All Flows Before Applying Route-Map--|") + pytest_assert(wait_until(60, 2, + lambda: __check_for_no_loss(snappi_api, + ['permit', 'permit_ipv6', + 'deny', 'deny_ipv6'], + PACKETS * 4)), + 'No loss expected') + + logger.info("|--Apply Route-Map--|") + # Apply route-map to permit only expected routes + route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'router bgp %s' " + "-c 'address-family ipv4 unicast' " + "-c 'neighbor LC route-map LA in' " + "-c 'address-family ipv6 unicast' " + "-c 'neighbor LCv6 route-map LAv6 in' " + ) + route_map %= (DUT_AS_NUM) + duthost.shell(route_map) + + # Start traffic + logger.info("|--Start Traffic--|") + ts = snappi_api.transmit_state() + ts.state = ts.START + snappi_api.set_transmit_state(ts) + + # Check there is no traffic loss for 'permit' and 'permit_ipv6' flow + logger.info( + "|--Assert No Loss For Flows With Permit--|") + pytest_assert(wait_until(60, 2, + lambda: __check_for_no_loss(snappi_api, + ['permit', 'permit_ipv6'], + PACKETS * 2)), + 'No loss expected') + + # Check 100% traffic loss for 'deny' and 'deny_ipv6' flow + logger.info( + "|--Assert 100 Percent Loss For Flows Without Permit--|") + pytest_assert(wait_until(60, 2, + lambda: __check_for_total_loss( + snappi_api, ['deny', 'deny_ipv6'])), + 'total loss expected') + + # Stop traffic + logger.info("|--Stopping Traffic After Test--|") + ts = snappi_api.transmit_state() + ts.state = ts.STOP + snappi_api.set_transmit_state(ts) + + +def __check_for_no_loss(snappi_api, + flow_names, + expected): + """ + Returns True if there is no traffic loss else False + + Args: + snappi_api (pytest fixture): Snappi API + flow_names: List of flow_names to check for validation + expected: Expected Packets Count + """ + request = snappi_api.metrics_request() + request.flow.flow_names = flow_names + flow_results = snappi_api.get_metrics(request).flow_metrics + flow_rx = sum([f.frames_rx for f in flow_results]) + return flow_rx == expected + + +def __check_for_total_loss(snappi_api, + flow_names): + """ + Returns True if there is 100% traffic loss else False + + Args: + snappi_api (pytest fixture): Snappi API + flow_names: List of flow_names to check for validation + """ + request = snappi_api.metrics_request() + request.flow.flow_names = flow_names + flow_results = snappi_api.get_metrics(request).flow_metrics + flow_rx = sum([f.frames_rx for f in flow_results]) + return flow_rx == 0 + + +def config_cleanup(duthost, + tgen_ports): + + # Remove bgp neighbor config + bgp_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no router bgp' " + ) + duthost.shell(bgp_config) + + # Remove any leftover config if not removed + route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no bgp community-list 10' " + ) + try: + duthost.shell(route_map) + except Exception: + pass + + route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no bgp as-path access-list PERMIT_100' " + ) + try: + duthost.shell(route_map) + except Exception: + pass + + route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no ip prefix-list PERMIT_IP' " + ) + try: + duthost.shell(route_map) + except Exception: + pass + + route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no ipv6 prefix-list PERMIT_IPV6' " + ) + try: + duthost.shell(route_map) + except Exception: + pass + + route_map = ( + "vtysh " + "-c 'configure terminal' " + "-c 'no route-map LA permit 30' " + "-c 'no route-map LAv6 permit 30' " + ) + try: + duthost.shell(route_map) + except Exception: + pass + + # Remove interface ip config + intf1_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'interface %s' " + "-c 'no ip address %s/%s' " + "-c 'no ipv6 address %s/%s' " + ) + intf1_config %= (tgen_ports[0]['peer_port'], + tgen_ports[0]['peer_ip'], + tgen_ports[0]['prefix'], + tgen_ports[0]['peer_ipv6'], + tgen_ports[0]['ipv6_prefix']) + duthost.shell(intf1_config) + + intf2_config = ( + "vtysh " + "-c 'configure terminal' " + "-c 'interface %s' " + "-c 'no ip address %s/%s' " + "-c 'no ipv6 address %s/%s' " + ) + intf2_config %= (tgen_ports[1]['peer_port'], + tgen_ports[1]['peer_ip'], + tgen_ports[1]['prefix'], + tgen_ports[1]['peer_ipv6'], + tgen_ports[1]['ipv6_prefix']) + duthost.shell(intf2_config) + diff --git a/tests/ixia/bgp/test_routing_policies.py b/tests/ixia/bgp/test_routing_policies.py new file mode 100644 index 00000000000..1c937489e00 --- /dev/null +++ b/tests/ixia/bgp/test_routing_policies.py @@ -0,0 +1,316 @@ +import pytest +import logging +from tests.common.ixia.ixia_fixtures import snappi_api +from tests.common.ixia.ixia_fixtures import ( + ixia_api_serv_ip, ixia_api_serv_port, tgen_ports) +from files.helper import ( + run_peer_routing_policies_test, run_community_list_filtering_test, + run_prefix_list_filtering_test, run_test_metric_filter, + run_group_as_path_modified, run_origin_code_modification, + config_setup, config_cleanup) +from tests.common.fixtures.conn_graph_facts import ( + conn_graph_facts, fanout_graph_facts) +logger = logging.getLogger(__name__) + + +@pytest.fixture(scope="module") +def setup_and_teardown(duthost, + tgen_ports): + """ + Setup and Teardown + """ + # We are going to use first two ports for all these tests + tgen_ports = tgen_ports[0:2] + logger.info("|--Common Setup Configuration--|") + config_setup(duthost, + tgen_ports) + yield + logger.info("|--Common Cleanup--|") + config_cleanup(duthost, + tgen_ports) + + +# Test 1 +@pytest.mark.topology("tgen") +def test_peer_routing_policies(snappi_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + setup_and_teardown): + """ + Topo: + TGEN1 --- DUT --- TGEN2 + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 + -- "200.1.0.0" & "4000::1" with Attributes + a) community-list 1:2 + b) as-path append AS 100 + c) Origin ebgp + d) Metric 50 + -- "20.1.0.0" & "6000::1" + 3) Create route-map in DUT to permit only "200.1.0.0" + & "4000::1" based on BGP Attributes + 4) Create four flows from TGEN2 to TGEN1 + a) 'permit' -- TGEN2 to TGEN1("200.1.0.0") + b) 'permit_ipv6' -- TGEN2 to TGEN1("4000::1") + c) 'deny' -- TGEN2 to TGEN1("20.1.0.0") + d) 'deny_ipv6' -- TGEN2 to TGEN1("6000::1") + + Verification: + 1) Send traffic without applying route-map + Result: Should not observe traffic loss in 'permit' & 'deny' + 'permit_ipv6' & 'deny_ipv6' + 2) Apply route-map + Result: Should observe 100% traffic loss in 'deny' & 'deny_ipv6' + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + """ + + tgen_ports = tgen_ports[0:2] + logger.info("|--BGP Peer Policies Test--|") + run_peer_routing_policies_test(snappi_api, + duthost, + tgen_ports) + + +# Test 2 +@pytest.mark.topology("tgen") +def test_community_list_filtering(snappi_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + setup_and_teardown): + """ + Topo: + TGEN1 --- DUT --- TGEN2 + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 + -- "200.1.0.0" & "4000::1" with Community Attribute 1:2 + -- "20.1.0.0" & "6000::1" + 3) Create route-map in DUT to permit only "200.1.0.0" + & "4000::1" based on Community Attribute + 4) Create four flows from TGEN2 to TGEN1 + a) 'permit' -- TGEN2 to TGEN1("200.1.0.0") + b) 'permit_ipv6' -- TGEN2 to TGEN1("4000::1") + c) 'deny' -- TGEN2 to TGEN1("20.1.0.0") + d) 'deny_ipv6' -- TGEN2 to TGEN1("6000::1") + + Verification: + 1) Send traffic without applying route-map + Result: Should not observe traffic loss in 'permit' & 'deny' + 'permit_ipv6' & 'deny_ipv6' + 2) Apply route-map + Result: Should observe 100% traffic loss in 'deny' & 'deny_ipv6' + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + """ + + tgen_ports = tgen_ports[0:2] + logger.info("|--BGP Community List Filtering Test--|") + run_community_list_filtering_test(snappi_api, + duthost, + tgen_ports) + + +# Test 3 +@pytest.mark.topology("tgen") +def test_prefix_list_filtering(snappi_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + setup_and_teardown): + """ + Topo: + TGEN1 --- DUT --- TGEN2 + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 + -- "200.1.0.0" & "4000::1" + -- "20.1.0.0" & "6000::1" + 3) Create Prefix-list route-map in DUT to permit + only "200.1.0.0" & "4000::1" + 4) Create four flows from TGEN2 to TGEN1 + a) 'permit' -- TGEN2 to TGEN1("200.1.0.0") + b) 'permit_ipv6' -- TGEN2 to TGEN1("4000::1") + c) 'deny' -- TGEN2 to TGEN1("20.1.0.0") + d) 'deny_ipv6' -- TGEN2 to TGEN1("6000::1") + + Verification: + 1) Send traffic without applying route-map + Result: Should not observe traffic loss in 'permit' & 'deny' + 'permit_ipv6' & 'deny_ipv6' + 2) Apply route-map + Result: Should observe 100% traffic loss in 'deny' & 'deny_ipv6' + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + """ + + tgen_ports = tgen_ports[0:2] + logger.info("|--BGP Prefix List Filtering Test--|") + run_prefix_list_filtering_test(snappi_api, + duthost, + tgen_ports) + + +# Test 4 +@pytest.mark.topology("tgen") +def test_metric_filter(snappi_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + setup_and_teardown): + """ + Topo: + TGEN1 --- DUT --- TGEN2 + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 + -- "200.1.0.0" & "4000::1" with Metric 50 + -- "20.1.0.0" & "6000::1" + 3) Create route-map in DUT to permit only "200.1.0.0" + & "4000::1" based on Metric + 4) Create four flows from TGEN2 to TGEN1 + a) 'permit' -- TGEN2 to TGEN1("200.1.0.0") + b) 'permit_ipv6' -- TGEN2 to TGEN1("4000::1") + c) 'deny' -- TGEN2 to TGEN1("20.1.0.0") + d) 'deny_ipv6' -- TGEN2 to TGEN1("6000::1") + + Verification: + 1) Send traffic without applying route-map + Result: Should not observe traffic loss in 'permit' & 'deny' + 'permit_ipv6' & 'deny_ipv6' + 2) Apply route-map + Result: Should observe 100% traffic loss in 'deny' & 'deny_ipv6' + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + """ + + tgen_ports = tgen_ports[0:2] + logger.info("|--BGP Metric Filter Test--|") + run_test_metric_filter(snappi_api, + duthost, + tgen_ports) + + +# Test 5 +@pytest.mark.topology("tgen") +def test_group_as_path_modified(snappi_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + setup_and_teardown): + """ + Topo: + TGEN1 --- DUT --- TGEN2 + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 + -- "200.1.0.0" & "4000::1" with group AS + -- "20.1.0.0" & "6000::1" + 3) Create route-map in DUT to permit only "200.1.0.0" + & "4000::1" based on group AS + 4) Create four flows from TGEN2 to TGEN1 + a) 'permit' -- TGEN2 to TGEN1("200.1.0.0") + b) 'permit_ipv6' -- TGEN2 to TGEN1("4000::1") + c) 'deny' -- TGEN2 to TGEN1("20.1.0.0") + d) 'deny_ipv6' -- TGEN2 to TGEN1("6000::1") + + Verification: + 1) Send traffic without applying route-map + Result: Should not observe traffic loss in 'permit' & 'deny' + 'permit_ipv6' & 'deny_ipv6' + 2) Apply route-map + Result: Should observe 100% traffic loss in 'deny' & 'deny_ipv6' + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + """ + + tgen_ports = tgen_ports[0:2] + logger.info("|--BGP group-as-path modified Test--|") + run_group_as_path_modified(snappi_api, + duthost, + tgen_ports) + + +# Test 6 +@pytest.mark.topology("tgen") +def test_origin_code_modification(snappi_api, + duthost, + tgen_ports, + conn_graph_facts, + fanout_graph_facts, + setup_and_teardown): + """ + Topo: + TGEN1 --- DUT --- TGEN2 + + Steps: + 1) Create BGP config on DUT and TGEN respectively + 2) Generate 2 ipv4 routes & 2 ipv6 routes from TGEN1 + -- "200.1.0.0" & "4000::1" with Origin 'egp' + -- "20.1.0.0" & "6000::1" + 3) Create route-map in DUT to permit only "200.1.0.0" + & "4000::1" based on Origin 'egp' + 4) Create four flows from TGEN2 to TGEN1 + a) 'permit' -- TGEN2 to TGEN1("200.1.0.0") + b) 'permit_ipv6' -- TGEN2 to TGEN1("4000::1") + c) 'deny' -- TGEN2 to TGEN1("20.1.0.0") + d) 'deny_ipv6' -- TGEN2 to TGEN1("6000::1") + + Verification: + 1) Send traffic without applying route-map + Result: Should not observe traffic loss in 'permit' & 'deny' + 'permit_ipv6' & 'deny_ipv6' + 2) Apply route-map + Result: Should observe 100% traffic loss in 'deny' & 'deny_ipv6' + + Args: + snappi_api (pytest fixture): Snappi API + duthost (pytest fixture): duthost fixture + tgen_ports (pytest fixture): Ports mapping info of T0 testbed + conn_graph_facts (pytest fixture): connection graph + fanout_graph_facts (pytest fixture): fanout graph + """ + + tgen_ports = tgen_ports[0:2] + logger.info("|--BGP Group-Origin Code Modifcation Test--|") + run_origin_code_modification(snappi_api, + duthost, + tgen_ports) \ No newline at end of file