diff --git a/tests/acl/templates/create_stress_acl_table.j2 b/tests/acl/templates/create_stress_acl_table.j2 new file mode 100644 index 00000000000..745b4df8f1e --- /dev/null +++ b/tests/acl/templates/create_stress_acl_table.j2 @@ -0,0 +1,12 @@ +[ + { + "op": "add", + "path": "/ACL_TABLE/STRESS_ACL_TABLE", + "value": { + "policy_desc": "STRESS_ACL_TABLE", + "type": "STRESS_ACL_TABLE_TYPE", + "stage": "INGRESS", + "ports": {{ bind_ports }} + } + } +] diff --git a/tests/acl/templates/stress_table_type.json b/tests/acl/templates/stress_table_type.json new file mode 100644 index 00000000000..df68634fc6d --- /dev/null +++ b/tests/acl/templates/stress_table_type.json @@ -0,0 +1,13 @@ +[ + { + "op": "add", + "path": "/ACL_TABLE_TYPE", + "value": { + "STRESS_ACL_TABLE_TYPE" : { + "MATCHES": ["DST_IP","DST_IPV6","ETHER_TYPE","IN_PORTS","L4_DST_PORT","L4_DST_PORT_RANGE","IP_PROTOCOL","IP_TYPE"], + "ACTIONS": ["PACKET_ACTION","COUNTER"], + "BIND_POINTS": ["PORT"] + } + } + } +] diff --git a/tests/acl/test_stress_acl.py b/tests/acl/test_stress_acl.py index 192c0506da4..dd8f6771abf 100644 --- a/tests/acl/test_stress_acl.py +++ b/tests/acl/test_stress_acl.py @@ -1,39 +1,90 @@ import logging -import random import pytest import json +import time +import netaddr import ptf.testutils as testutils from ptf import mask, packet -from collections import defaultdict from tests.common.dualtor.mux_simulator_control import toggle_all_simulator_ports_to_rand_selected_tor # noqa F401 from tests.common.utilities import wait_until +from tests.common.helpers.assertions import pytest_assert pytestmark = [ - pytest.mark.topology("t0", "t1", "m0", "mx"), - pytest.mark.device_type('vs') + pytest.mark.topology("t0") ] logger = logging.getLogger(__name__) -LOOP_TIMES_LEVEL_MAP = { - 'debug': 10, - 'basic': 50, - 'confident': 200 -} -# Template json file used to test scale rules -STRESS_ACL_TABLE_TEMPLATE = "acl/templates/acltb_test_stress_acl_table.j2" -STRESS_ACL_RULE_TEMPLATE = "acl/templates/acltb_test_stress_acl_rules.j2" -STRESS_ACL_READD_RULE_TEMPLATE = "acl/templates/acltb_test_stress_acl_readd_rules.j2" -DEL_STRESS_ACL_TABLE_TEMPLATE = "acl/templates/del_acltb_test_stress_acl_table.j2" -STRESS_ACL_TABLE_JSON_FILE = "/tmp/acltb_test_stress_acl_table.json" -STRESS_ACL_RULE_JSON_FILE = "/tmp/acltb_test_stress_acl_rules.json" -DEL_STRESS_ACL_TABLE_JSON_FILE = "/tmp/del_acltb_test_stress_acl_table.json" +STRESS_ACL_TABLE_TYPE_NAME = "STRESS_ACL_TABLE_TYPE" +STRESS_ACL_TABLE_NAME = "STRESS_ACL_TABLE" + +STRESS_ACL_TABLE_TYPE_SRC = "acl/templates/stress_table_type.json" +STRESS_ACL_TABLE_TYPE_DST = "/tmp/stress_table_type.json" + +STRESS_ACL_TABLE_CREATE_JSON_SRC = "acl/templates/create_stress_acl_table.j2" +STRESS_ACL_TABLE_CREATE_JSON_DST = "/tmp/create_stress_acl_table.json" + +STRESS_ACL_RULE_JSON_FILE = "/tmp/stress_acl_rules.json" +STRESS_ACL_RULE_V4_REMOVE_JSON_FILE = "/tmp/stress_acl_rules_v4_remove.json" +STRESS_ACL_RULE_V6_REMOVE_JSON_FILE = "/tmp/stress_acl_rules_v6_remove.json" +STRESS_ACL_RULE_V4_ADD_JSON_FILE = "/tmp/stress_acl_rules_v4_add.json" +STRESS_ACL_RULE_V6_ADD_JSON_FILE = "/tmp/stress_acl_rules_v6_add.json" +STRESS_ACL_RULE_V4_UPDATE_JSON_FILE = "/tmp/stress_acl_rules_v4_update.json" +STRESS_ACL_RULE_V6_UPDATE_JSON_FILE = "/tmp/stress_acl_rules_v6_update.json" + +STRESS_ACL_RULE_GROUPS = { + # IPv4 rules that never changed + "RULE_IPV4_GROUP_1": [], + # IPv4 rules that will be updated + "RULE_IPV4_GROUP_2": [], + # IPv4 rules that will be used to overwrite rules in group 2 + "RULE_IPV4_GROUP_3": [], + # IPv6 rules that never changed + "RULE_IPV6_GROUP_1": [], + # IPv6 rules that will be updated + "RULE_IPV6_GROUP_2": [], + # IPv6 rules that will be used to overwrite rules in group 2 + "RULE_IPV6_GROUP_3": [] +} -LOG_EXPECT_ACL_TABLE_CREATE_RE = ".*Created ACL table.*" -LOG_EXPECT_ACL_RULE_FAILED_RE = ".*Failed to create ACL rule.*" -ACL_RULE_NUMS = 10 +def prepare_stress_acl_rules(): + """ + A helper function to generate 700 stress acl rules + """ + global STRESS_ACL_RULE_GROUPS + count = 1 + # 250 IPv4 rules in group 1 + RULE_TEMPLATE = "123.1.1.{}" + for i in range(1, 251): + STRESS_ACL_RULE_GROUPS["RULE_IPV4_GROUP_1"].append((count, RULE_TEMPLATE.format(i))) + count += 1 + # 100 IPv4 rules in group 2 + RULE_TEMPLATE = "123.1.2.{}" + for i in range(1, 101): + STRESS_ACL_RULE_GROUPS["RULE_IPV4_GROUP_2"].append((count, RULE_TEMPLATE.format(i))) + count += 1 + # 100 IPv4 rules in group 3 + RULE_TEMPLATE = "123.1.3.{}" + for i in range(1, 101): + STRESS_ACL_RULE_GROUPS["RULE_IPV4_GROUP_3"].append( + (STRESS_ACL_RULE_GROUPS["RULE_IPV4_GROUP_2"][i - 1][0], RULE_TEMPLATE.format(i))) + # 250 IPv6 rules in group 1 + RULE_TEMPLATE = "2001:db8:1:1::{}" + for i in range(1, 251): + STRESS_ACL_RULE_GROUPS["RULE_IPV6_GROUP_1"].append((count, RULE_TEMPLATE.format(i))) + count += 1 + # 100 IPv6 rules in group 2 + RULE_TEMPLATE = "2001:db8:1:2::{}" + for i in range(1, 101): + STRESS_ACL_RULE_GROUPS["RULE_IPV6_GROUP_2"].append((count, RULE_TEMPLATE.format(i))) + count += 1 + # 100 IPv6 rules in group 3 + RULE_TEMPLATE = "2001:db8:1:3::{}" + for i in range(1, 101): + STRESS_ACL_RULE_GROUPS["RULE_IPV6_GROUP_3"].append( + (STRESS_ACL_RULE_GROUPS["RULE_IPV6_GROUP_2"][i - 1][0], RULE_TEMPLATE.format(i))) @pytest.fixture(scope="module", autouse=True) @@ -73,148 +124,361 @@ def remove_dataacl_table(duthosts, rand_selected_dut): rand_selected_dut.shell(cmd_create_table) -@pytest.fixture(scope='module') -def prepare_test_file(rand_selected_dut): - # Define a custom table type CUSTOM_TYPE by loading a json configuration - rand_selected_dut.copy(src=STRESS_ACL_TABLE_TEMPLATE, dest=STRESS_ACL_TABLE_JSON_FILE, mode="0755") - rand_selected_dut.shell("sonic-cfggen -j {} -w".format(STRESS_ACL_TABLE_JSON_FILE)) - # Copy acl rules - rand_selected_dut.copy(src=STRESS_ACL_RULE_TEMPLATE, dest=STRESS_ACL_RULE_JSON_FILE, mode="0755") +@pytest.fixture(scope="module") +def setup_info(rand_selected_dut, tbinfo): + """ + A fixture to get test setup info + """ + setup_info = {} - yield + mg_facts = rand_selected_dut.get_extended_minigraph_facts(tbinfo) - rand_selected_dut.copy(src=DEL_STRESS_ACL_TABLE_TEMPLATE, dest=DEL_STRESS_ACL_TABLE_JSON_FILE) - rand_selected_dut.shell("configlet -d -j {}".format(DEL_STRESS_ACL_TABLE_JSON_FILE)) - rand_selected_dut.shell("rm -f {}".format(DEL_STRESS_ACL_TABLE_JSON_FILE)) + # Get router MAC + vlan_name = list(mg_facts['minigraph_vlans'].keys())[0] + if "dualtor" in tbinfo["topo"]["name"]: + # Use VLAN MAC as router MAC on dual-tor testbed + setup_info['router_mac'] = rand_selected_dut.get_dut_iface_mac(vlan_name) + setup_info['is_dualtor'] = True + else: + setup_info['router_mac'] = rand_selected_dut.facts['router_mac'] + setup_info['is_dualtor'] = False + + # Get the list of upstream/downstream ports + downstream_ports = [] + upstream_ports = [] + downstream_port_ids = [] + upstream_port_ids = [] + # Put all VLAN members into downstream_ports + downstream_ports = list(mg_facts["minigraph_vlans"][vlan_name]["members"]) + downstream_port_ids = [mg_facts['minigraph_ptf_indices'][port_name] for port_name in downstream_ports] + # Put all portchannel members into dst_ports + for _, v in mg_facts['minigraph_portchannels'].items(): + for member in v['members']: + upstream_port_ids.append(mg_facts['minigraph_ptf_indices'][member]) + upstream_ports.append(member) -@pytest.fixture(scope='module') -def prepare_test_port(rand_selected_dut, tbinfo): - mg_facts = rand_selected_dut.get_extended_minigraph_facts(tbinfo) + setup_info['downstream_ports'] = downstream_ports + setup_info['upstream_ports'] = upstream_ports + setup_info['downstream_port_ids'] = downstream_port_ids + setup_info['upstream_port_ids'] = upstream_port_ids - ports = list(mg_facts['minigraph_portchannels']) - if not ports: - ports = mg_facts["minigraph_acls"]["DataAcl"] + yield setup_info - dut_port = ports[0] if ports else None - if not dut_port: - pytest.skip('No portchannels nor dataacl ports found') - if "Ethernet" in dut_port: - dut_eth_port = dut_port - elif "PortChannel" in dut_port: - dut_eth_port = mg_facts["minigraph_portchannels"][dut_port]["members"][0] - ptf_src_port = mg_facts["minigraph_ptf_indices"][dut_eth_port] +@pytest.fixture(scope="module") +def setup_stress_acl_table(rand_selected_dut, setup_info): + """ + Create a custom ACL table (combined V4 and V6) for testing + """ + # Step 1: Define a custom ACL table type STRESS_ACL_TABLE_TYPE by loading a json configuration + rand_selected_dut.copy(src=STRESS_ACL_TABLE_TYPE_SRC, dest=STRESS_ACL_TABLE_TYPE_DST, mode="0755") + rand_selected_dut.shell("config apply-patch {}".format(STRESS_ACL_TABLE_TYPE_DST)) + time.sleep(5) + # Step 2: Create a custom ACL table of type STRESS_ACL_TABLE_TYPE. The table is bound to all Vlan ports + extra_vars = { + 'bind_ports': setup_info['downstream_ports'] + } + rand_selected_dut.host.options['variable_manager'].extra_vars.update(extra_vars) + rand_selected_dut.template(src=STRESS_ACL_TABLE_CREATE_JSON_SRC, dest=STRESS_ACL_TABLE_CREATE_JSON_DST) + rand_selected_dut.shell("sed -i \"s/'/\\\"/g\" " + STRESS_ACL_TABLE_CREATE_JSON_DST) + rand_selected_dut.shell("config apply-patch {}".format(STRESS_ACL_TABLE_CREATE_JSON_DST)) + time.sleep(5) + # Check if the table is created successfully + acl_table_status = rand_selected_dut.show_and_parse('show acl table {}'.format(STRESS_ACL_TABLE_NAME)) + pytest_assert(acl_table_status[0]['status'].lower() == 'active', "Failed to create ACL table") - topo = tbinfo["topo"]["type"] - # Get the list of upstream ports - upstream_ports = defaultdict(list) - upstream_port_ids = [] - for interface, neighbor in list(mg_facts["minigraph_neighbors"].items()): - port_id = mg_facts["minigraph_ptf_indices"][interface] - if (topo == "t1" and "T2" in neighbor["name"]) or (topo == "t0" and "T1" in neighbor["name"]) or \ - (topo == "m0" and "M1" in neighbor["name"]) or (topo == "mx" and "M0" in neighbor["name"]): - upstream_ports[neighbor['namespace']].append(interface) - upstream_port_ids.append(port_id) + yield - return ptf_src_port, upstream_port_ids, dut_port + # Remove ACL table STRESS_ACL_TABLE + rand_selected_dut.shell("config acl remove table {}".format(STRESS_ACL_TABLE_NAME)) + # Remove custom ACL table type STRESS_ACL_TABLE_TYPE + rand_selected_dut.shell("sonic-db-cli CONFIG_DB del \"ACL_TABLE_TYPE|{}\"".format(STRESS_ACL_TABLE_TYPE_NAME)) -def verify_acl_rules(rand_selected_dut, ptfadapter, ptf_src_port, - ptf_dst_ports, acl_rule_list, del_rule_id, verity_status): +def prepare_acl_rule_update_files(duthost, group_names, file_name, oper="add", default_drop_rule=False): + """ + Copy json files for update test to DUT + """ + patch = [] + + if oper == "add": + patch.append({}) + patch[0]["path"] = "/ACL_RULE" + patch[0]["value"] = {} + patch[0]["op"] = "add" + + for group in group_names: + for id, ip in STRESS_ACL_RULE_GROUPS[group]: + if oper == "add": + if netaddr.IPAddress(ip).version == 4: + key = "DST_IP" + ip_mask = ip + "/32" + else: + key = "DST_IPV6" + ip_mask = ip + "/128" + rule = { + "{}|RULE_{}".format(STRESS_ACL_TABLE_NAME, id): { + "PRIORITY": 900 - id, + "PACKET_ACTION": "FORWARD", + key: ip_mask + } + } + patch[0]["value"].update(rule) + else: + rule = { + "op": "remove", + "path": "/ACL_RULE/{}|RULE_{}".format(STRESS_ACL_TABLE_NAME, id) + } + patch.append(rule) + if default_drop_rule: + # Add a default rule to drop all other traffic + patch[0]["value"].update({ + "{}|RULE_DROP_2".format(STRESS_ACL_TABLE_NAME): { + "PRIORITY": 2, + "IP_TYPE": "IPV6ANY", + "PACKET_ACTION": "DROP" + }, + "{}|RULE_DROP_1".format(STRESS_ACL_TABLE_NAME): { + "PRIORITY": 1, + "ETHER_TYPE": 0x0800, + "PACKET_ACTION": "DROP" + } + }) + # Dump json to file + TMP_FILE = "/tmp/tmp_acl_rules.json" + with open(TMP_FILE, "w") as f: + json.dump(patch, f) + # Copy json file to DUT + duthost.copy(src=TMP_FILE, dest=file_name, mode="0755") + duthost.shell("sed -i \"s/'/\\\"/g\" " + file_name) + + +def apply_acl_rule_patch(duthost, file_name, group_names=(), oper="add"): + """ + Apply patch to DUT + """ + duthost.shell("config apply-patch {}".format(file_name), module_ignore_errors=True) + rule_list = [] + for group_name in group_names: + for id, _ in STRESS_ACL_RULE_GROUPS[group_name]: + rule_list.append("RULE_{}".format(id)) + if oper == "add": + # For add operation, check and confirm all rules are active + def _check_acl_rule_status(): + count = 0 + acl_rule_status = duthost.show_and_parse('show acl rule {}'.format(STRESS_ACL_TABLE_NAME)) + for rule in acl_rule_status: + if rule['rule'] in rule_list and rule['status'].lower() == 'active': + count += 1 + return count == len(rule_list) + wait_until(60, 5, 10, _check_acl_rule_status, "Not all ACL rules are active") + else: + # For remove operation, delay for 30 seconds to let the rules removed + time.sleep(30) + + +@pytest.fixture(scope="module") +def setup_stress_acl_rules_cli(rand_selected_dut, setup_stress_acl_table): + """ + Fixture to create stress acl rules with redis-db cli + """ + prepare_stress_acl_rules() + yield + # Remove all ACL rules + rand_selected_dut.shell("acl-loader delete {}".format(STRESS_ACL_TABLE_NAME)) + - for acl_id in acl_rule_list: - ip_addr1 = acl_id % 256 - ip_addr2 = int(acl_id / 256) +@pytest.fixture(scope="module") +def setup_stress_acl_rules(rand_selected_dut, setup_stress_acl_table): + """ + Fixture to create stress acl rules + """ + prepare_stress_acl_rules() + group_names = ["RULE_IPV4_GROUP_1", "RULE_IPV4_GROUP_2", "RULE_IPV6_GROUP_1", "RULE_IPV6_GROUP_2"] + prepare_acl_rule_update_files(rand_selected_dut, + group_names, + file_name=STRESS_ACL_RULE_JSON_FILE, + default_drop_rule=True) + # Copy other json files to DUT + prepare_acl_rule_update_files(rand_selected_dut, ["RULE_IPV4_GROUP_2"], + STRESS_ACL_RULE_V4_REMOVE_JSON_FILE, oper="remove"), + prepare_acl_rule_update_files(rand_selected_dut, ["RULE_IPV6_GROUP_2"], + STRESS_ACL_RULE_V6_REMOVE_JSON_FILE, oper="remove"), + prepare_acl_rule_update_files(rand_selected_dut, ["RULE_IPV4_GROUP_3"], + STRESS_ACL_RULE_V4_ADD_JSON_FILE, oper="add"), + prepare_acl_rule_update_files(rand_selected_dut, ["RULE_IPV6_GROUP_3"], + STRESS_ACL_RULE_V6_ADD_JSON_FILE, oper="add") - src_ip_addr = "20.0.{}.{}".format(ip_addr2, ip_addr1) - dst_ip_addr = "10.0.0.1" - pkt = testutils.simple_ip_packet( - eth_dst=rand_selected_dut.facts['router_mac'], + yield + # Remove all ACL rules + rand_selected_dut.shell("acl-loader delete {}".format(STRESS_ACL_TABLE_NAME)) + + +def add_acl_rules(duthost, group_name, fwd=True, default_drop_rule=False): + """ + Add ACL rules + """ + cmds = [] + rule_list = [] + if fwd: + action = "FORWARD" + else: + action = "DROP" + for id, ip in STRESS_ACL_RULE_GROUPS[group_name]: + if netaddr.IPAddress(ip).version == 4: + key = "DST_IP" + ip_mask = ip + "/32" + else: + key = "DST_IPV6" + ip_mask = ip + "/128" + cmds.append( + "sonic-db-cli CONFIG_DB hmset \'ACL_RULE|{}|RULE_{}\' {} {} PRIORITY {} PACKET_ACTION {}".format( + STRESS_ACL_TABLE_NAME, id, key, ip_mask, 900 - id, action)) + rule_list.append("RULE_{}".format(id)) + + if default_drop_rule: + cmds.append( + "sonic-db-cli CONFIG_DB hmset \'ACL_RULE|{}|RULE_DROP_2\' IP_TYPE IPV6ANY PRIORITY 2 PACKET_ACTION DROP" + .format(STRESS_ACL_TABLE_NAME)) + cmds.append( + "sonic-db-cli CONFIG_DB hmset \'ACL_RULE|{}|RULE_DROP_1\' ETHER_TYPE 0x0800 PRIORITY 1 PACKET_ACTION DROP" + .format(STRESS_ACL_TABLE_NAME)) + rule_list.extend(["RULE_DROP_1", "RULE_DROP_2"]) + + duthost.shell_cmds(cmds=cmds) + + # Verify all rules are active + def _check_acl_rule_status(): + count = 0 + acl_rule_status = duthost.show_and_parse('show acl rule {}'.format(STRESS_ACL_TABLE_NAME)) + for rule in acl_rule_status: + if rule['rule'] in rule_list and rule['status'].lower() == 'active': + count += 1 + return count == len(rule_list) + + pytest_assert(wait_until(0.5*len(rule_list), 5, 10, _check_acl_rule_status), "Not all ACL rules are active") + + +def remove_acl_rules(duthost, group_name): + """ + Remove ACL rules + """ + cmds = [] + for id, _ in STRESS_ACL_RULE_GROUPS[group_name]: + cmds.append("sonic-db-cli CONFIG_DB del \'ACL_RULE|{}|RULE_{}\'".format(STRESS_ACL_TABLE_NAME, id)) + duthost.shell_cmds(cmds=cmds) + # There is no way to verify rules are removed from ASIC, so we just wait for a few seconds + time.sleep(0.5 * len(cmds)) + + +def verify_acl_rules(rand_selected_dut, ptfadapter, ptf_src_port, ptf_dst_ports, router_mac, ip, fwd=True): + """ + Build testing packet to veryfy ACL rule + """ + if netaddr.IPAddress(ip).version == 4: + pkt = testutils.simple_udp_packet( + eth_dst=router_mac, eth_src=ptfadapter.dataplane.get_mac(0, ptf_src_port), - ip_src=src_ip_addr, - ip_dst=dst_ip_addr, - ip_proto=47, - ip_tos=0x84, - ip_id=0, - ip_ihl=5, - ip_ttl=121 + ip_src="192.168.0.100", + ip_dst=ip ) pkt_copy = pkt.copy() - pkt_copy.ttl = pkt_copy.ttl - 1 + pkt_copy['IP'].ttl -= 1 exp_pkt = mask.Mask(pkt_copy) exp_pkt.set_do_not_care_scapy(packet.Ether, 'dst') exp_pkt.set_do_not_care_scapy(packet.Ether, 'src') exp_pkt.set_do_not_care_scapy(packet.IP, "chksum") + else: + pkt = testutils.simple_udpv6_packet( + eth_dst=router_mac, + eth_src=ptfadapter.dataplane.get_mac(0, ptf_src_port), + ipv6_src="fc02:1000::100", + ipv6_dst=ip + ) + pkt_copy = pkt.copy() + pkt_copy['IPv6'].hlim -= 1 + exp_pkt = mask.Mask(pkt_copy) + exp_pkt.set_do_not_care_scapy(packet.Ether, 'dst') + exp_pkt.set_do_not_care_scapy(packet.Ether, 'src') + exp_pkt.set_do_not_care_scapy(packet.UDP, "chksum") + RETRY = 3 + while RETRY > 0: ptfadapter.dataplane.flush() testutils.send(test=ptfadapter, port_id=ptf_src_port, pkt=pkt) - if verity_status == "forward" or acl_id == del_rule_id: - testutils.verify_packet_any_port(test=ptfadapter, pkt=exp_pkt, ports=ptf_dst_ports) - elif verity_status == "drop" and acl_id != del_rule_id: + if fwd: + try: + testutils.verify_packet_any_port(test=ptfadapter, pkt=exp_pkt, ports=ptf_dst_ports) + except Exception as e: + if RETRY == 0: + raise e + else: + logger.info("Retrying...") + RETRY -= 1 + else: + break + else: testutils.verify_no_packet_any(test=ptfadapter, pkt=exp_pkt, ports=ptf_dst_ports) + break -def acl_rule_loaded(rand_selected_dut, acl_rule_list): - acl_rule_infos = rand_selected_dut.show_and_parse("show acl rule") - acl_id_list = [] - for acl_info in acl_rule_infos: - acl_id = int(acl_info['rule'][len('RULE_'):]) - acl_id_list.append(acl_id) - if sorted(acl_id_list) != sorted(acl_rule_list): - return False - return True - - -def test_acl_add_del_stress(rand_selected_dut, tbinfo, ptfadapter, prepare_test_file, - prepare_test_port, get_function_completeness_level, - toggle_all_simulator_ports_to_rand_selected_tor): # noqa F811 - - ptf_src_port, ptf_dst_ports, dut_port = prepare_test_port - - cmd_create_table = "config acl add table STRESS_ACL L3 -s ingress -p {}".format(dut_port) - cmd_remove_table = "config acl remove table STRESS_ACL" - cmd_add_rules = "sonic-cfggen -j {} -w".format(STRESS_ACL_RULE_JSON_FILE) - cmd_rm_all_rules = "acl-loader delete STRESS_ACL" - - normalized_level = get_function_completeness_level - if normalized_level is None: - normalized_level = 'debug' - loop_times = LOOP_TIMES_LEVEL_MAP[normalized_level] - wait_timeout = 15 - - rand_selected_dut.shell(cmd_create_table) - acl_rule_list = list(range(1, ACL_RULE_NUMS + 1)) - verify_acl_rules(rand_selected_dut, ptfadapter, ptf_src_port, ptf_dst_ports, acl_rule_list, 0, "forward") - try: - loops = 0 - while loops <= loop_times: - logger.info("loops: {}".format(loops)) - if loops == 0: - rand_selected_dut.shell(cmd_add_rules) - else: - readd_id = loops + ACL_RULE_NUMS - ip_addr1 = readd_id % 256 - ip_addr2 = int(readd_id / 256) - rand_selected_dut.shell('sonic-db-cli CONFIG_DB hset "ACL_RULE|STRESS_ACL| RULE_{}" \ - "SRC_IP" "20.0.{}.{}/32" "PACKET_ACTION" "DROP" "PRIORITY" "{}"' - .format(readd_id, ip_addr2, ip_addr1, readd_id)) - acl_rule_list.append(readd_id) - - wait_until(wait_timeout, 2, 0, acl_rule_loaded, rand_selected_dut, acl_rule_list) - verify_acl_rules(rand_selected_dut, ptfadapter, ptf_src_port, ptf_dst_ports, acl_rule_list, 0, "drop") - - del_rule_id = random.choice(acl_rule_list) - rand_selected_dut.shell('sonic-db-cli CONFIG_DB del "ACL_RULE|STRESS_ACL| RULE_{}"'.format(del_rule_id)) - acl_rule_list.remove(del_rule_id) - - wait_until(wait_timeout, 2, 0, acl_rule_loaded, rand_selected_dut, acl_rule_list) - verify_acl_rules(rand_selected_dut, ptfadapter, ptf_src_port, ptf_dst_ports, - acl_rule_list, del_rule_id, "drop") - - loops += 1 - finally: - rand_selected_dut.shell(cmd_rm_all_rules) - rand_selected_dut.shell(cmd_remove_table) - logger.info("End") +def verify_acl_rules_group(rand_selected_dut, ptfadapter, setup_info, group_name, fwd=True): + """ + Verify ACL rules in a group + """ + ptf_src_port, ptf_dst_ports, router_mac = setup_info['downstream_port_ids'][0], setup_info['upstream_port_ids'], \ + setup_info['router_mac'] + for id, ip in STRESS_ACL_RULE_GROUPS[group_name]: + verify_acl_rules(rand_selected_dut, ptfadapter, ptf_src_port, ptf_dst_ports, router_mac, ip, fwd=fwd) + + +def test_stress_acl_with_custom_acl_table(rand_selected_dut, tbinfo, ptfadapter, setup_info, setup_stress_acl_rules_cli, + toggle_all_simulator_ports_to_rand_selected_tor): # noqa F811 + """ + Test stress acl with custom acl table + """ + LOOP = 1000 + group_names = ["RULE_IPV4_GROUP_1", "RULE_IPV4_GROUP_2", "RULE_IPV6_GROUP_1", "RULE_IPV6_GROUP_2"] + + for i in range(LOOP): + logger.info("Stress ACL test loop: {}".format(i)) + logger.info("Creating ACL rules") + # Apply patch + for group in group_names: + add_acl_rules(rand_selected_dut, group, fwd=True, default_drop_rule=True) + # Verify all ACL rules + logger.info("Verifying all ACL rules") + for group in group_names: + verify_acl_rules_group(rand_selected_dut, ptfadapter, setup_info, group, fwd=True) + + # Update 1: Remove all the rules in "RULE_IPV4_GROUP_2" + logger.info("Removing IPv4 ACL rules") + remove_acl_rules(rand_selected_dut, "RULE_IPV4_GROUP_2") + logger.info("Verifying IPv4 ACL rules are removed") + verify_acl_rules_group(rand_selected_dut, ptfadapter, setup_info, "RULE_IPV4_GROUP_2", fwd=False) + + # Update 2: Add a new set of IPv4 rules in "RULE_IPV4_GROUP_3" + logger.info("Adding new IPv4 ACL rules") + add_acl_rules(rand_selected_dut, "RULE_IPV4_GROUP_3", fwd=True) + logger.info("Verifying new IPv4 ACL rules") + verify_acl_rules_group(rand_selected_dut, ptfadapter, setup_info, "RULE_IPV4_GROUP_3", fwd=True) + + # Update 3: Remove all the rules in "RULE_IPV6_GROUP_2" + logger.info("Removing IPv6 ACL rules") + remove_acl_rules(rand_selected_dut, "RULE_IPV6_GROUP_2") + logger.info("Verifying IPv6 ACL rules are removed") + verify_acl_rules_group(rand_selected_dut, ptfadapter, setup_info, "RULE_IPV6_GROUP_2", fwd=False) + + # Update 4: Add a new set of IPv6 rules in "RULE_IPV6_GROUP_3" + logger.info("Adding new IPv6 ACL rules") + add_acl_rules(rand_selected_dut, "RULE_IPV6_GROUP_3", fwd=True) + logger.info("Verifying new IPv6 ACL rules") + verify_acl_rules_group(rand_selected_dut, ptfadapter, setup_info, "RULE_IPV6_GROUP_3", fwd=True) + + # Update 5: Remove all ACL rules + logger.info("Removing all ACL rules") + rand_selected_dut.shell("acl-loader delete {}".format(STRESS_ACL_TABLE_NAME)) + + logger.info("Stress ACL test loop {} done".format(i))