diff --git a/orchagent/aclorch.cpp b/orchagent/aclorch.cpp index 8dd92a2f23..ed7365d087 100644 --- a/orchagent/aclorch.cpp +++ b/orchagent/aclorch.cpp @@ -69,7 +69,11 @@ acl_rule_attr_lookup_t aclMatchLookup = { MATCH_INNER_ETHER_TYPE, SAI_ACL_ENTRY_ATTR_FIELD_INNER_ETHER_TYPE }, { MATCH_INNER_IP_PROTOCOL, SAI_ACL_ENTRY_ATTR_FIELD_INNER_IP_PROTOCOL }, { MATCH_INNER_L4_SRC_PORT, SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_SRC_PORT }, - { MATCH_INNER_L4_DST_PORT, SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_DST_PORT } + { MATCH_INNER_L4_DST_PORT, SAI_ACL_ENTRY_ATTR_FIELD_INNER_L4_DST_PORT }, + { MATCH_SRC_MAC, SAI_ACL_ENTRY_ATTR_FIELD_SRC_MAC }, + { MATCH_DST_MAC, SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC }, + { MATCH_OUTER_VLAN_PRI, SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_PRI}, + { MATCH_OUTER_VLAN_CFI, SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_CFI} }; static acl_range_type_lookup_t aclRangeTypeLookup = @@ -195,6 +199,26 @@ static acl_table_action_list_lookup_t defaultAclActionList = } } }, + { + // L2 + TABLE_TYPE_L2, + { + { + ACL_STAGE_INGRESS, + { + SAI_ACL_ACTION_TYPE_PACKET_ACTION, + SAI_ACL_ACTION_TYPE_REDIRECT + } + }, + { + ACL_STAGE_EGRESS, + { + SAI_ACL_ACTION_TYPE_PACKET_ACTION, + SAI_ACL_ACTION_TYPE_REDIRECT + } + } + } + }, { // MIRROR TABLE_TYPE_MIRROR, @@ -926,6 +950,41 @@ bool AclRule::validateAddMatch(string attr_name, string attr_value) matchData.data.u8 = to_uint(attr_value); matchData.mask.u8 = 0xFF; } + else if (attr_name == MATCH_SRC_MAC || attr_name == MATCH_DST_MAC) + { + auto mask_and_value = tokenize(attr_value, '/'); + MacAddress mac(mask_and_value[0]); + memcpy(matchData.data.mac, mac.getMac(), sizeof(sai_mac_t)); + if (mask_and_value.size() > 1) + { + MacAddress mask(mask_and_value[1]); + memcpy(matchData.mask.mac, mask.getMac(), sizeof(sai_mac_t)); + } + else + { + const sai_mac_t mac_mask = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + memcpy(matchData.mask.mac, mac_mask, sizeof(sai_mac_t)); + } + } + else if (attr_name == MATCH_OUTER_VLAN_PRI) + { + auto vlan_pri = tokenize(attr_value, '/'); + + matchData.data.u8 = to_uint(vlan_pri[0], 0, 0x7); + if (vlan_pri.size() > 1) + { + matchData.mask.u8 = to_uint(vlan_pri[1], 0, 0x7); + } + else + { + matchData.mask.u8 = 0x7; + } + } + else if (attr_name == MATCH_OUTER_VLAN_CFI) + { + matchData.data.u8 = to_uint(attr_value); + matchData.mask.u8 = 0x1; + } } catch (exception &e) { @@ -3048,6 +3107,20 @@ void AclOrch::initDefaultTableTypes() .build() ); + addAclTableType( + builder.withName(TABLE_TYPE_L2) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_MAC)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_MAC)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_OUTER_VLAN_ID)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_OUTER_VLAN_PRI)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_OUTER_VLAN_CFI)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE)) + .build() + ); + addAclTableType( builder.withName(TABLE_TYPE_MCLAG) .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) diff --git a/orchagent/aclorch.h b/orchagent/aclorch.h index 737f5516a0..f93a03d89f 100644 --- a/orchagent/aclorch.h +++ b/orchagent/aclorch.h @@ -49,6 +49,10 @@ #define MATCH_INNER_IP_PROTOCOL "INNER_IP_PROTOCOL" #define MATCH_INNER_L4_SRC_PORT "INNER_L4_SRC_PORT" #define MATCH_INNER_L4_DST_PORT "INNER_L4_DST_PORT" +#define MATCH_SRC_MAC "SRC_MAC" +#define MATCH_DST_MAC "DST_MAC" +#define MATCH_OUTER_VLAN_PRI "VLAN_PCP" +#define MATCH_OUTER_VLAN_CFI "VLAN_DEI" #define BIND_POINT_TYPE_PORT "PORT" #define BIND_POINT_TYPE_PORTCHANNEL "PORTCHANNEL" diff --git a/orchagent/acltable.h b/orchagent/acltable.h index 2d91a84b98..cab0d5a931 100644 --- a/orchagent/acltable.h +++ b/orchagent/acltable.h @@ -34,6 +34,7 @@ extern "C" { #define TABLE_TYPE_MCLAG "MCLAG" #define TABLE_TYPE_MUX "MUX" #define TABLE_TYPE_DROP "DROP" +#define TABLE_TYPE_L2 "L2" typedef enum { diff --git a/tests/test_acl.py b/tests/test_acl.py index ac7e7fda87..5f1e1acf30 100644 --- a/tests/test_acl.py +++ b/tests/test_acl.py @@ -24,6 +24,12 @@ PFCWD_TABLE_TYPE = "PFCWD" PFCWD_TABLE_NAME = "PFCWD_TEST" PFCWD_BIND_PORTS = ["Ethernet0", "Ethernet4", "Ethernet8", "Ethernet12"] + +L2_TABLE_TYPE = "L2" +L2_TABLE_NAME = "L2_TEST" +L2_BIND_PORTS = ["Ethernet0", "Ethernet4", "Ethernet8", "Ethernet12"] +L2_RULE_NAME = "L2_TEST_RULE" + class TestAcl: @pytest.fixture def l3_acl_table(self, dvs_acl): @@ -63,6 +69,15 @@ def mirror_acl_table(self, dvs_acl): dvs_acl.remove_acl_table(MIRROR_TABLE_NAME) dvs_acl.verify_acl_table_count(0) + @pytest.fixture + def l2_acl_table(self, dvs_acl): + try: + dvs_acl.create_acl_table(L2_TABLE_NAME, L2_TABLE_TYPE, L2_BIND_PORTS) + yield dvs_acl.get_acl_table_ids(1)[0] + finally: + dvs_acl.remove_acl_table(L2_TABLE_NAME) + dvs_acl.verify_acl_table_count(0) + @pytest.fixture(params=['ingress', 'egress']) def pfcwd_acl_table(self, dvs_acl, request): try: @@ -577,6 +592,51 @@ def test_AclTableMandatoryMatchFields(self, dvs, pfcwd_acl_table): assert match_in_ports else: assert not match_in_ports + def test_L2AclRuleSrcMac(self, dvs_acl, l2_acl_table): + config_qualifiers = {"SRC_MAC": "00:00:00:11:11:11/ff:ff:ff:ff:ff:ff"} + expected_sai_qualifiers = { + "SAI_ACL_ENTRY_ATTR_FIELD_SRC_MAC": dvs_acl.get_simple_qualifier_comparator("00:00:00:11:11:11&mask:FF:FF:FF:FF:FF:FF") + } + + dvs_acl.create_acl_rule(L2_TABLE_NAME, L2_RULE_NAME, config_qualifiers) + dvs_acl.verify_acl_rule(expected_sai_qualifiers) + + dvs_acl.remove_acl_rule(L2_TABLE_NAME, L2_RULE_NAME) + dvs_acl.verify_no_acl_rules() + def test_L2AclRuleDstMac(self, dvs_acl, l2_acl_table): + config_qualifiers = {"DST_MAC": "00:00:00:22:22:22/ff:ff:ff:ff:ff:ff"} + expected_sai_qualifiers = { + "SAI_ACL_ENTRY_ATTR_FIELD_DST_MAC": dvs_acl.get_simple_qualifier_comparator("00:00:00:22:22:22&mask:FF:FF:FF:FF:FF:FF") + } + + dvs_acl.create_acl_rule(L2_TABLE_NAME, L2_RULE_NAME, config_qualifiers) + dvs_acl.verify_acl_rule(expected_sai_qualifiers) + + dvs_acl.remove_acl_rule(L2_TABLE_NAME, L2_RULE_NAME) + dvs_acl.verify_no_acl_rules() + def test_L2AclRuleVlanPri(self, dvs_acl, l2_acl_table): + config_qualifiers = {"VLAN_PCP": "5/7"} + expected_sai_qualifiers = { + "SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_PRI": dvs_acl.get_simple_qualifier_comparator("5&mask:0x7") + } + + dvs_acl.create_acl_rule(L2_TABLE_NAME, L2_RULE_NAME, config_qualifiers) + dvs_acl.verify_acl_rule(expected_sai_qualifiers) + + dvs_acl.remove_acl_rule(L2_TABLE_NAME, L2_RULE_NAME) + dvs_acl.verify_no_acl_rules() + def test_L2AclRuleVlanCfi(self, dvs_acl, l2_acl_table): + config_qualifiers = {"VLAN_DEI": "1"} + expected_sai_qualifiers = { + "SAI_ACL_ENTRY_ATTR_FIELD_OUTER_VLAN_CFI": dvs_acl.get_simple_qualifier_comparator("1&mask:0x1") + } + + dvs_acl.create_acl_rule(L2_TABLE_NAME, L2_RULE_NAME, config_qualifiers) + dvs_acl.verify_acl_rule(expected_sai_qualifiers) + + dvs_acl.remove_acl_rule(L2_TABLE_NAME, L2_RULE_NAME) + dvs_acl.verify_no_acl_rules() + class TestAclCrmUtilization: @pytest.fixture(scope="class", autouse=True) def configure_crm_polling_interval_for_test(self, dvs):