diff --git a/doc/Configuration.md b/doc/Configuration.md index 039e749d378d..40865366f624 100644 --- a/doc/Configuration.md +++ b/doc/Configuration.md @@ -286,6 +286,46 @@ and migration plan ``` +***ACL table type configuration example*** +``` +{ + "ACL_TABLE_TYPE": { + "CUSTOM_L3": { + "MATCHES": [ + "IN_PORTS", + "OUT_PORTS", + "SRC_IP" + ], + "ACTIONS": [ + "PACKET_ACTION", + "MIRROR_INGRESS_ACTION" + ], + "BIND_POINTS": [ + "PORT", + "LAG" + ] + } + }, + "ACL_TABLE": { + "DATAACL": { + "STAGE": "INGRESS", + "TYPE": "CUSTOM_L3", + "PORTS": [ + "Ethernet0", + "PortChannel1" + ] + } + }, + "ACL_RULE": { + "DATAACL|RULE0": { + "PRIORITY": "999", + "PACKET_ACTION": "DROP", + "SRC_IP": "1.1.1.1/32", + } + } +} +``` + ### BGP Sessions BGP session configuration is defined in **BGP_NEIGHBOR** table. BGP diff --git a/doc/swss-schema.md b/doc/swss-schema.md index 1fe9ef9b2cbb..ec28eb6c0f3b 100644 --- a/doc/swss-schema.md +++ b/doc/swss-schema.md @@ -569,15 +569,37 @@ It's possible to create separate configuration files for different ASIC platform ---------------------------------------------- +### ACL\_TABLE\_TYPE +Stores a definition of table - set of matches, actions and bind point types. ACL_TABLE references a key inside this table in "type" field. + +``` +key: ACL_TABLE_TYPE:name ; key of the ACL table type entry. The name is arbitary name user chooses. +; field = value +matches = match-list ; list of matches for this table, matches are same as in ACL_RULE table. +actions = action-list ; list of actions for this table, actions are same as in ACL_RULE table. +bind_points = bind-points-list ; list of bind point types for this table. + +; values annotation +match = 1*64VCHAR +match-list = [1-max-matches]*match +action = 1*64VCHAR +action-list = [1-max-actions]*action +bind-point = port/lag +bind-points-list = [1-max-bind-points]*bind-point +``` + ### ACL\_TABLE Stores information about ACL tables on the switch. Port names are defined in [port_config.ini](../portsyncd/port_config.ini). key = ACL_TABLE:name ; acl_table_name must be unique ;field = value policy_desc = 1*255VCHAR ; name of the ACL policy table description - type = "mirror"/"l3"/"l3v6" ; type of acl table, every type of + type = 1*255VCHAR ; type of acl table, every type of ; table defines the match/action a ; specific set of match and actions. + ; There are pre-defined table types like + ; "MIRROR", "MIRRORV6", "MIRROR_DSCP", + ; "L3", "L3V6", "MCLAG", "PFCWD", "DROP". ports = [0-max_ports]*port_name ; the ports to which this ACL ; table is applied, can be emtry ; value annotations diff --git a/orchagent/aclorch.cpp b/orchagent/aclorch.cpp index e3b279a482db..900299b3d5c7 100644 --- a/orchagent/aclorch.cpp +++ b/orchagent/aclorch.cpp @@ -32,7 +32,10 @@ extern CrmOrch *gCrmOrch; #define MIN_VLAN_ID 1 // 0 is a reserved VLAN ID #define MAX_VLAN_ID 4095 // 4096 is a reserved VLAN ID +#define STATE_DB_ACL_ACTION_FIELD_IS_ACTION_LIST_MANDATORY "is_action_list_mandatory" +#define STATE_DB_ACL_ACTION_FIELD_ACTION_LIST "action_list" #define COUNTERS_ACL_COUNTER_RULE_MAP "ACL_COUNTER_RULE_MAP" + #define ACL_COUNTER_DEFAULT_POLLING_INTERVAL_MS 10000 // ms #define ACL_COUNTER_DEFAULT_ENABLED_STATE false @@ -75,6 +78,12 @@ static acl_range_type_lookup_t aclRangeTypeLookup = { MATCH_L4_DST_PORT_RANGE, SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE }, }; +static acl_bind_point_type_lookup_t aclBindPointTypeLookup = +{ + { BIND_POINT_TYPE_PORT, SAI_ACL_BIND_POINT_TYPE_PORT }, + { BIND_POINT_TYPE_PORTCHANNEL, SAI_ACL_BIND_POINT_TYPE_LAG }, +}; + static acl_rule_attr_lookup_t aclL3ActionLookup = { { ACTION_PACKET_ACTION, SAI_ACL_ENTRY_ATTR_ACTION_PACKET_ACTION }, @@ -112,20 +121,6 @@ static acl_dtel_flow_op_type_lookup_t aclDTelFlowOpTypeLookup = { DTEL_FLOW_OP_IOAM, SAI_ACL_DTEL_FLOW_OP_IOAM } }; -static acl_table_type_lookup_t aclTableTypeLookUp = -{ - { TABLE_TYPE_L3, ACL_TABLE_L3 }, - { TABLE_TYPE_L3V6, ACL_TABLE_L3V6 }, - { TABLE_TYPE_MIRROR, ACL_TABLE_MIRROR }, - { TABLE_TYPE_MIRRORV6, ACL_TABLE_MIRRORV6 }, - { TABLE_TYPE_MIRROR_DSCP, ACL_TABLE_MIRROR_DSCP }, - { TABLE_TYPE_CTRLPLANE, ACL_TABLE_CTRLPLANE }, - { TABLE_TYPE_DTEL_FLOW_WATCHLIST, ACL_TABLE_DTEL_FLOW_WATCHLIST }, - { TABLE_TYPE_DTEL_DROP_WATCHLIST, ACL_TABLE_DTEL_DROP_WATCHLIST }, - { TABLE_TYPE_MCLAG, ACL_TABLE_MCLAG }, - { TABLE_TYPE_DROP, ACL_TABLE_DROP } -}; - static acl_stage_type_lookup_t aclStageLookUp = { {STAGE_INGRESS, ACL_STAGE_INGRESS }, @@ -136,16 +131,24 @@ static const acl_capabilities_t defaultAclActionsSupported = { { ACL_STAGE_INGRESS, + AclActionCapabilities { - SAI_ACL_ACTION_TYPE_PACKET_ACTION, - SAI_ACL_ACTION_TYPE_MIRROR_INGRESS, - SAI_ACL_ACTION_TYPE_NO_NAT + { + SAI_ACL_ACTION_TYPE_PACKET_ACTION, + SAI_ACL_ACTION_TYPE_MIRROR_INGRESS, + SAI_ACL_ACTION_TYPE_NO_NAT + }, + false } }, { ACL_STAGE_EGRESS, + AclActionCapabilities { - SAI_ACL_ACTION_TYPE_PACKET_ACTION + { + SAI_ACL_ACTION_TYPE_PACKET_ACTION + }, + false } } }; @@ -170,6 +173,24 @@ static map aclCounterLookup = {SAI_ACL_COUNTER_ATTR_ENABLE_PACKET_COUNT, SAI_ACL_COUNTER_ATTR_PACKETS}, }; +static sai_acl_table_attr_t AclEntryFieldToAclTableField(sai_acl_entry_attr_t attr) +{ + if (!IS_ATTR_ID_IN_RANGE(attr, ACL_ENTRY, FIELD)) + { + SWSS_LOG_THROW("ACL entry attribute is not a in a range of SAI_ACL_ENTRY_ATTR_FIELD_* attribute: %d", attr); + } + return static_cast(SAI_ACL_TABLE_ATTR_FIELD_START + (attr - SAI_ACL_ENTRY_ATTR_FIELD_START)); +} + +static sai_acl_action_type_t AclEntryActionToAclAction(sai_acl_entry_attr_t attr) +{ + if (!IS_ATTR_ID_IN_RANGE(attr, ACL_ENTRY, ACTION)) + { + SWSS_LOG_THROW("ACL entry attribute is not a in a range of SAI_ACL_ENTRY_ATTR_ACTION_* attribute: %d", attr); + } + return static_cast(attr - SAI_ACL_ENTRY_ATTR_ACTION_START); +} + static string getAttributeIdName(sai_object_type_t objectType, sai_attr_id_t attr) { const auto* meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_ACL_ENTRY, attr); @@ -180,18 +201,284 @@ static string getAttributeIdName(sai_object_type_t objectType, sai_attr_id_t att return meta->attridname; } -AclRule::AclRule(AclOrch *pAclOrch, string rule, string table, acl_table_type_t type, bool createCounter) : +AclTableMatchInterface::AclTableMatchInterface(sai_acl_table_attr_t matchField): + m_matchField(matchField) +{ + if (!IS_ATTR_ID_IN_RANGE(m_matchField, ACL_TABLE, FIELD)) + { + SWSS_LOG_THROW("Invalid match table attribute %d", m_matchField); + } +} + +sai_acl_table_attr_t AclTableMatchInterface::getId() const +{ + return m_matchField; +} + +AclTableMatch::AclTableMatch(sai_acl_table_attr_t matchField): + AclTableMatchInterface(matchField) +{ + const auto meta = sai_metadata_get_attr_metadata(SAI_OBJECT_TYPE_ACL_TABLE, getId()); + if (!meta) + { + SWSS_LOG_THROW("Failed to get metadata for attribute for SAI_OBJECT_TYPE_ACL_TABLE: attribute %d", getId()); + } + + if (meta->attrvaluetype != SAI_ATTR_VALUE_TYPE_BOOL) + { + SWSS_LOG_THROW("This API does not allow to set match with a non boolean value type"); + } +} + +sai_attribute_t AclTableMatch::toSaiAttribute() +{ + return sai_attribute_t{ + .id = getId(), + .value = { + .booldata = true, + }, + }; +} + +bool AclTableMatch::validateAclRuleMatch(const AclRule& rule) const +{ + // no need to validate rule configuration + return true; +} + +AclTableRangeMatch::AclTableRangeMatch(set rangeTypes): + AclTableMatchInterface(SAI_ACL_TABLE_ATTR_FIELD_ACL_RANGE_TYPE), + m_rangeList(rangeTypes.begin(), rangeTypes.end()) +{ +} + +sai_attribute_t AclTableRangeMatch::toSaiAttribute() +{ + return sai_attribute_t{ + .id = getId(), + .value = { + .s32list = { + .count = static_cast(m_rangeList.size()), + .list = m_rangeList.data(), + }, + }, + }; +} + +bool AclTableRangeMatch::validateAclRuleMatch(const AclRule& rule) const +{ + const auto& rangeConfig = rule.getRangeConfig(); + for (const auto& range: rangeConfig) + { + if (find(m_rangeList.begin(), m_rangeList.end(), range.rangeType) == m_rangeList.end()) + { + SWSS_LOG_ERROR("Range match %s is not supported on table %s", + sai_metadata_get_acl_range_type_name(range.rangeType), rule.getTableId().c_str()); + return false; + } + } + + return true; +} + +string AclTableType::getName() const +{ + return m_name; +} + +const set& AclTableType::getBindPointTypes() const +{ + return m_bpointTypes; +} + +const map>& AclTableType::getMatches() const +{ + return m_matches; +} + +const set& AclTableType::getActions() const +{ + return m_aclAcitons; +} + +AclTableTypeBuilder& AclTableTypeBuilder::withName(string name) +{ + m_tableType.m_name = name; + return *this; +} + +AclTableTypeBuilder& AclTableTypeBuilder::withBindPointType(sai_acl_bind_point_type_t bpointType) +{ + m_tableType.m_bpointTypes.insert(bpointType); + return *this; +} + +AclTableTypeBuilder& AclTableTypeBuilder::withMatch(shared_ptr match) +{ + m_tableType.m_matches.emplace(match->getId(), match); + return *this; +} + +AclTableTypeBuilder& AclTableTypeBuilder::withAction(sai_acl_action_type_t action) +{ + m_tableType.m_aclAcitons.insert(action); + return *this; +} + +AclTableType AclTableTypeBuilder::build() +{ + auto tableType = m_tableType; + m_tableType = AclTableType(); + return tableType; +} + +bool AclTableTypeParser::parse(const std::string& key, + const vector& fieldValues, + AclTableTypeBuilder& builder) +{ + builder.withName(key); + + for (const auto& fieldValue: fieldValues) + { + auto field = to_upper(fvField(fieldValue)); + auto value = to_upper(fvValue(fieldValue)); + + SWSS_LOG_DEBUG("field %s, value %s", field.c_str(), value.c_str()); + + if (field == ACL_TABLE_TYPE_MATCHES) + { + if (!parseAclTableTypeMatches(value, builder)) + { + return false; + } + } + else if (field == ACL_TABLE_TYPE_ACTIONS) + { + if (!parseAclTableTypeActions(value, builder)) + { + return false; + } + } + else if (field == ACL_TABLE_TYPE_BPOINT_TYPES) + { + if (!parseAclTableTypeBindPointTypes(value, builder)) + { + return false; + } + } + else + { + SWSS_LOG_ERROR("Unknown field %s: value %s", field.c_str(), value.c_str()); + return false; + } + } + + return true; +} + +bool AclTableTypeParser::parseAclTableTypeMatches(const std::string& value, AclTableTypeBuilder& builder) +{ + auto matches = tokenize(value, comma); + set saiRangeTypes; + + for (const auto& match: matches) + { + auto matchIt = aclMatchLookup.find(match); + auto rangeMatchIt = aclRangeTypeLookup.find(match); + + if (rangeMatchIt != aclRangeTypeLookup.end()) + { + auto rangeType = rangeMatchIt->second; + saiRangeTypes.insert(rangeType); + } + else if (matchIt != aclMatchLookup.end()) + { + auto saiMatch = AclEntryFieldToAclTableField(matchIt->second); + builder.withMatch(make_unique(saiMatch)); + } + else + { + SWSS_LOG_ERROR("Unknown match %s", match.c_str()); + return false; + } + } + + if (!saiRangeTypes.empty()) + { + builder.withMatch(make_unique(saiRangeTypes)); + } + + return true; +} + +bool AclTableTypeParser::parseAclTableTypeActions(const std::string& value, AclTableTypeBuilder& builder) +{ + auto actions = tokenize(value, comma); + for (const auto& action: actions) + { + sai_acl_entry_attr_t saiActionAttr = SAI_ACL_ENTRY_ATTR_ACTION_END; + + auto l3Action = aclL3ActionLookup.find(action); + auto mirrorAction = aclMirrorStageLookup.find(action); + auto dtelAction = aclDTelActionLookup.find(action); + + if (l3Action != aclL3ActionLookup.end()) + { + saiActionAttr = l3Action->second; + } + else if (mirrorAction != aclMirrorStageLookup.end()) + { + saiActionAttr = mirrorAction->second; + } + else if (dtelAction != aclDTelActionLookup.end()) + { + saiActionAttr = dtelAction->second; + } + else + { + SWSS_LOG_ERROR("Unknown action %s", action.c_str()); + return false; + } + + builder.withAction(AclEntryActionToAclAction(saiActionAttr)); + } + + return true; +} + +bool AclTableTypeParser::parseAclTableTypeBindPointTypes(const std::string& value, AclTableTypeBuilder& builder) +{ + auto bpointTypes = tokenize(value, comma); + for (const auto& bpointType: bpointTypes) + { + auto bpointIt = aclBindPointTypeLookup.find(bpointType); + if (bpointIt == aclBindPointTypeLookup.end()) + { + SWSS_LOG_ERROR("Unknown bind point %s", bpointType.c_str()); + return false; + } + + auto saiBpointType = bpointIt->second; + builder.withBindPointType(saiBpointType); + } + + return true; +} + +AclRule::AclRule(AclOrch *pAclOrch, string rule, string table, bool createCounter) : m_pAclOrch(pAclOrch), m_id(rule), - m_tableId(table), - m_tableType(type), - m_tableOid(SAI_NULL_OBJECT_ID), m_ruleOid(SAI_NULL_OBJECT_ID), m_counterOid(SAI_NULL_OBJECT_ID), m_priority(0), m_createCounter(createCounter) { - m_tableOid = pAclOrch->getTableById(m_tableId); + auto tableOid = pAclOrch->getTableById(table); + m_pTable = pAclOrch->getTableByOid(tableOid); + if (!m_pTable) + { + SWSS_LOG_THROW("Failed to find ACL table %s. ACL table must exist at the time of creating AclRule", table.c_str()); + } } bool AclRule::validateAddPriority(string attr_name, string attr_value) @@ -396,7 +683,7 @@ bool AclRule::validateAddMatch(string attr_name, string attr_value) m_rangeConfig.push_back(rangeConfig); - return true; + return m_pTable->validateAclRuleMatch(SAI_ACL_ENTRY_ATTR_FIELD_ACL_RANGE_TYPE, *this); } else if (attr_name == MATCH_TC) { @@ -439,7 +726,7 @@ bool AclRule::validateAddMatch(string attr_name, string attr_value) // TODO: For backwards compatibility, users can substitute IP_PROTOCOL for NEXT_HEADER. // This should be removed in a future release. - if ((m_tableType == ACL_TABLE_MIRRORV6 || m_tableType == ACL_TABLE_L3V6) + if ((m_pTable->type.getName() == TABLE_TYPE_MIRRORV6 || m_pTable->type.getName() == TABLE_TYPE_L3V6) && attr_name == MATCH_IP_PROTOCOL) { SWSS_LOG_WARN("Support for IP protocol on IPv6 tables will be removed in a future release, please switch to using NEXT_HEADER instead!"); @@ -485,7 +772,6 @@ bool AclRule::createRule() { SWSS_LOG_ENTER(); - sai_object_id_t table_oid = m_pAclOrch->getTableById(m_tableId); vector rule_attrs; sai_object_id_t range_objects[2]; sai_object_list_t range_object_list = {0, range_objects}; @@ -495,7 +781,7 @@ bool AclRule::createRule() // store table oid this rule belongs to attr.id = SAI_ACL_ENTRY_ATTR_TABLE_ID; - attr.value.oid = table_oid; + attr.value.oid = m_pTable->getOid(); rule_attrs.push_back(attr); attr.id = SAI_ACL_ENTRY_ATTR_PRIORITY; @@ -562,7 +848,7 @@ bool AclRule::createRule() decreaseNextHopRefCount(); } - gCrmOrch->incCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_ENTRY, m_tableOid); + gCrmOrch->incCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_ENTRY, m_pTable->getOid()); return (status == SAI_STATUS_SUCCESS); } @@ -599,13 +885,7 @@ void AclRule::decreaseNextHopRefCount() bool AclRule::isActionSupported(sai_acl_entry_attr_t action) const { - auto action_type = AclOrch::getAclActionFromAclEntry(action); - const auto* pTable = m_pAclOrch->getTableByOid(m_tableOid); - if (pTable == nullptr) - { - SWSS_LOG_THROW("ACL table does not exist for oid %" PRIu64, m_tableOid); - } - return m_pAclOrch->isAclActionSupported(pTable->stage, action_type); + return m_pAclOrch->isAclActionSupported(m_pTable->stage, AclEntryActionToAclAction(action)); } bool AclRule::removeRule() @@ -624,7 +904,7 @@ bool AclRule::removeRule() return false; } - gCrmOrch->decCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_ENTRY, m_tableOid); + gCrmOrch->decCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_ENTRY, m_pTable->getOid()); m_ruleOid = SAI_NULL_OBJECT_ID; @@ -870,7 +1150,7 @@ bool AclRule::setAction(sai_acl_entry_attr_t actionId, sai_acl_action_data_t act if (meta->isenum) { // if ACL action attribute requires enum value check if value is supported by the ASIC - if (!m_pAclOrch->isAclActionEnumValueSupported(AclOrch::getAclActionFromAclEntry(actionId), actionData.parameter)) + if (!m_pAclOrch->isAclActionEnumValueSupported(AclEntryActionToAclAction(actionId), actionData.parameter)) { SWSS_LOG_ERROR("Action %s is not supported by ASIC", getAttributeIdName(SAI_OBJECT_TYPE_ACL_ENTRY, actionId).c_str()); @@ -884,6 +1164,11 @@ bool AclRule::setAction(sai_acl_entry_attr_t actionId, sai_acl_action_data_t act m_actions[actionId] = SaiAttrWrapper(SAI_OBJECT_TYPE_ACL_ENTRY, attr); + if (!m_pTable->validateAclRuleAction(actionId, *this)) + { + return false; + } + return true; } @@ -895,6 +1180,11 @@ bool AclRule::setMatch(sai_acl_entry_attr_t matchId, sai_acl_field_data_t matchD m_matches[matchId] = SaiAttrWrapper(SAI_OBJECT_TYPE_ACL_ENTRY, attr); + if (!m_pTable->validateAclRuleMatch(matchId, *this)) + { + return false; + } + return true; } @@ -936,94 +1226,78 @@ vector AclRule::getInPorts() const return inPorts; } -shared_ptr AclRule::makeShared(acl_table_type_t type, AclOrch *acl, MirrorOrch *mirror, DTelOrch *dtel, const string& rule, const string& table, const KeyOpFieldsValuesTuple& data) +string AclRule::getId() const { - string action; - bool action_found = false; - /* Find action configured by user. Based on action type create rule. */ - for (const auto& itr : kfvFieldsValues(data)) - { - string attr_name = to_upper(fvField(itr)); - string attr_value = fvValue(itr); - if (aclL3ActionLookup.find(attr_name) != aclL3ActionLookup.cend() || - aclMirrorStageLookup.find(attr_name) != aclMirrorStageLookup.cend() || - /* handle "MIRROR_ACTION" key without mirror stage specified for backward compatibility */ - attr_name == ACTION_MIRROR_ACTION || - aclDTelActionLookup.find(attr_name) != aclDTelActionLookup.cend()) - { - action_found = true; - action = attr_name; - break; - } - } + return m_id; +} - if (!action_found) - { - throw runtime_error("ACL rule action is not found in rule " + rule); - } +string AclRule::getTableId() const +{ + return m_pTable->getId(); +} - if (type != ACL_TABLE_L3 && - type != ACL_TABLE_L3V6 && - type != ACL_TABLE_MIRROR && - type != ACL_TABLE_MIRRORV6 && - type != ACL_TABLE_MIRROR_DSCP && - type != ACL_TABLE_DTEL_FLOW_WATCHLIST && - type != ACL_TABLE_DTEL_DROP_WATCHLIST && - type != ACL_TABLE_MCLAG && - type != ACL_TABLE_DROP) - { - throw runtime_error("Unknown table type"); - } +sai_object_id_t AclRule::getOid() const +{ + return m_ruleOid; +} - /* Mirror rules can exist in both tables */ - if (aclMirrorStageLookup.find(action) != aclMirrorStageLookup.cend() || - action == ACTION_MIRROR_ACTION /* implicitly ingress in old schema */) - { - return make_shared(acl, mirror, rule, table, type); - } - /* L3 rules can exist only in L3 table */ - else if (type == ACL_TABLE_L3) - { - return make_shared(acl, rule, table, type); - } - /* L3V6 rules can exist only in L3V6 table */ - else if (type == ACL_TABLE_L3V6) - { - return make_shared(acl, rule, table, type); - } - /* Pfcwd rules can exist only in PFCWD table */ - else if (type == ACL_TABLE_PFCWD) - { - return make_shared(acl, rule, table, type); - } - else if (type == ACL_TABLE_DTEL_FLOW_WATCHLIST) +sai_object_id_t AclRule::getCounterOid() const +{ + return m_counterOid; +} + +bool AclRule::hasCounter() const +{ + return getCounterOid() != SAI_NULL_OBJECT_ID; +} + +const vector& AclRule::getRangeConfig() const +{ + return m_rangeConfig; +} + +shared_ptr AclRule::makeShared(AclOrch *acl, MirrorOrch *mirror, DTelOrch *dtel, const string& rule, const string& table, const KeyOpFieldsValuesTuple& data) +{ + shared_ptr aclRule; + + for (const auto& itr: kfvFieldsValues(data)) { - if (dtel) + auto action = to_upper(fvField(itr)); + if (aclMirrorStageLookup.find(action) != aclMirrorStageLookup.cend() || + action == ACTION_MIRROR_ACTION /* implicitly ingress in old schema */) { - return make_shared(acl, dtel, rule, table, type); - } else { - throw runtime_error("DTel feature is not enabled. Watchlists cannot be configured"); + return make_shared(acl, mirror, rule, table); } - } - else if (type == ACL_TABLE_DTEL_DROP_WATCHLIST) - { - if (dtel) + else if (aclL3ActionLookup.find(action) != aclL3ActionLookup.cend()) { - return make_shared(acl, dtel, rule, table, type); - } else { - throw runtime_error("DTel feature is not enabled. Watchlists cannot be configured"); + return make_shared(acl, rule, table); + } + else if (aclDTelFlowOpTypeLookup.find(action) != aclDTelFlowOpTypeLookup.cend()) + { + if (!dtel) + { + throw runtime_error("DTel feature is not enabled. Watchlists cannot be configured"); + } + + if (action == ACTION_DTEL_DROP_REPORT_ENABLE || + action == ACTION_DTEL_TAIL_DROP_REPORT_ENABLE || + action == ACTION_DTEL_REPORT_ALL_PACKETS) + { + return make_shared(acl, dtel, rule, table); + } + else + { + return make_shared(acl, dtel, rule, table); + } } } - else if (type == ACL_TABLE_MCLAG) - { - return make_shared(acl, rule, table, type); - } - else if (type == ACL_TABLE_DROP) + + if (!aclRule) { - return make_shared(acl, rule, table, type); + throw runtime_error("ACL rule action is not found in rule " + rule); } - throw runtime_error("Wrong combination of table type and action in rule " + rule); + return aclRule; } bool AclRule::enableCounter() @@ -1037,7 +1311,7 @@ bool AclRule::enableCounter() if (m_ruleOid == SAI_NULL_OBJECT_ID) { - SWSS_LOG_ERROR("ACL rule %s doesn't exist in ACL table %s", m_id.c_str(), m_tableId.c_str()); + SWSS_LOG_ERROR("ACL rule %s doesn't exist in ACL table %s", m_id.c_str(), m_pTable->getId().c_str()); return false; } @@ -1055,7 +1329,7 @@ bool AclRule::enableCounter() sai_status_t status = sai_acl_api->set_acl_entry_attribute(m_ruleOid, &attr); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to enable counter for ACL rule %s in ACL table %s", m_id.c_str(), m_tableId.c_str()); + SWSS_LOG_ERROR("Failed to enable counter for ACL rule %s in ACL table %s", m_id.c_str(), m_pTable->getId().c_str()); removeCounter(); return false; } @@ -1074,7 +1348,7 @@ bool AclRule::disableCounter() if (m_ruleOid == SAI_NULL_OBJECT_ID) { - SWSS_LOG_ERROR("ACL rule %s doesn't exist in ACL table %s", m_id.c_str(), m_tableId.c_str()); + SWSS_LOG_ERROR("ACL rule %s doesn't exist in ACL table %s", m_id.c_str(), m_pTable->getId().c_str()); return false; } @@ -1087,7 +1361,7 @@ bool AclRule::disableCounter() sai_status_t status = sai_acl_api->set_acl_entry_attribute(m_ruleOid, &attr); if (status != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to disable counter for ACL rule %s in ACL table %s", m_id.c_str(), m_tableId.c_str()); + SWSS_LOG_ERROR("Failed to disable counter for ACL rule %s in ACL table %s", m_id.c_str(), m_pTable->getId().c_str()); return false; } @@ -1112,7 +1386,7 @@ bool AclRule::createCounter() } attr.id = SAI_ACL_COUNTER_ATTR_TABLE_ID; - attr.value.oid = m_tableOid; + attr.value.oid = m_pTable->getOid(); counter_attrs.push_back(attr); for (const auto& counterAttrPair: aclCounterLookup) @@ -1124,13 +1398,13 @@ bool AclRule::createCounter() if (sai_acl_api->create_acl_counter(&m_counterOid, gSwitchId, (uint32_t)counter_attrs.size(), counter_attrs.data()) != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to create counter for the rule %s in table %s", m_id.c_str(), m_tableId.c_str()); + SWSS_LOG_ERROR("Failed to create counter for the rule %s in table %s", m_id.c_str(), m_pTable->getId().c_str()); return false; } - gCrmOrch->incCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_COUNTER, m_tableOid); + gCrmOrch->incCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_COUNTER, m_pTable->getOid()); - SWSS_LOG_INFO("Created counter for the rule %s in table %s", m_id.c_str(), m_tableId.c_str()); + SWSS_LOG_INFO("Created counter for the rule %s in table %s", m_id.c_str(), m_pTable->getId().c_str()); return true; } @@ -1159,25 +1433,25 @@ bool AclRule::removeCounter() if (sai_acl_api->remove_acl_counter(m_counterOid) != SAI_STATUS_SUCCESS) { - SWSS_LOG_ERROR("Failed to remove ACL counter for rule %s in table %s", m_id.c_str(), m_tableId.c_str()); + SWSS_LOG_ERROR("Failed to remove ACL counter for rule %s in table %s", m_id.c_str(), m_pTable->getId().c_str()); return false; } - gCrmOrch->decCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_COUNTER, m_tableOid); + gCrmOrch->decCrmAclTableUsedCounter(CrmResourceType::CRM_ACL_COUNTER, m_pTable->getOid()); m_counterOid = SAI_NULL_OBJECT_ID; - SWSS_LOG_INFO("Removed counter for the rule %s in table %s", m_id.c_str(), m_tableId.c_str()); + SWSS_LOG_INFO("Removed counter for the rule %s in table %s", m_id.c_str(), m_pTable->getId().c_str()); return true; } -AclRuleL3::AclRuleL3(AclOrch *aclOrch, string rule, string table, acl_table_type_t type, bool createCounter) : - AclRule(aclOrch, rule, table, type, createCounter) +AclRulePacket::AclRulePacket(AclOrch *aclOrch, string rule, string table, bool createCounter) : + AclRule(aclOrch, rule, table, createCounter) { } -bool AclRuleL3::validateAddAction(string attr_name, string _attr_value) +bool AclRulePacket::validateAddAction(string attr_name, string _attr_value) { SWSS_LOG_ENTER(); @@ -1253,7 +1527,7 @@ bool AclRuleL3::validateAddAction(string attr_name, string _attr_value) } // This method should return sai attribute id of the redirect destination -sai_object_id_t AclRuleL3::getRedirectObjectId(const string& redirect_value) +sai_object_id_t AclRulePacket::getRedirectObjectId(const string& redirect_value) { string target = redirect_value; @@ -1326,36 +1600,7 @@ sai_object_id_t AclRuleL3::getRedirectObjectId(const string& redirect_value) return SAI_NULL_OBJECT_ID; } -bool AclRuleL3::validateAddMatch(string attr_name, string attr_value) -{ - if (attr_name == MATCH_DSCP) - { - SWSS_LOG_ERROR("DSCP match is not supported for table type L3"); - return false; - } - - if (attr_name == MATCH_SRC_IPV6 || attr_name == MATCH_DST_IPV6) - { - SWSS_LOG_ERROR("IPv6 address match is not supported for table type L3"); - return false; - } - - if (attr_name == MATCH_ICMPV6_TYPE || attr_name == MATCH_ICMPV6_CODE) - { - SWSS_LOG_ERROR("ICMPv6 match is not supported for table type L3"); - return false; - } - - if (attr_name == MATCH_NEXT_HEADER) - { - SWSS_LOG_ERROR("IPv6 Next Header match is not supported for table type L3"); - return false; - } - - return AclRule::validateAddMatch(attr_name, attr_value); -} - -bool AclRuleL3::validate() +bool AclRulePacket::validate() { SWSS_LOG_ENTER(); @@ -1367,80 +1612,21 @@ bool AclRuleL3::validate() return true; } -void AclRuleL3::onUpdate(SubjectType, void *) +void AclRulePacket::onUpdate(SubjectType, void *) { // Do nothing } -AclRulePfcwd::AclRulePfcwd(AclOrch *aclOrch, string rule, string table, acl_table_type_t type, bool createCounter) : - AclRuleL3(aclOrch, rule, table, type, createCounter) +AclRuleMirror::AclRuleMirror(AclOrch *aclOrch, MirrorOrch *mirror, string rule, string table) : + AclRule(aclOrch, rule, table), + m_state(false), + m_pMirrorOrch(mirror) { } -bool AclRulePfcwd::validateAddMatch(string attr_name, string attr_value) +bool AclRuleMirror::validateAddAction(string attr_name, string attr_value) { - return AclRule::validateAddMatch(attr_name, attr_value); -} - -AclRuleMux::AclRuleMux(AclOrch *aclOrch, string rule, string table, acl_table_type_t type, bool createCounter) : - AclRuleL3(aclOrch, rule, table, type, createCounter) -{ -} - -bool AclRuleMux::validateAddMatch(string attr_name, string attr_value) -{ - return AclRule::validateAddMatch(attr_name, attr_value); -} - -AclRuleL3V6::AclRuleL3V6(AclOrch *aclOrch, string rule, string table, acl_table_type_t type) : - AclRuleL3(aclOrch, rule, table, type) -{ -} - - -bool AclRuleL3V6::validateAddMatch(string attr_name, string attr_value) -{ - if (attr_name == MATCH_DSCP) - { - SWSS_LOG_ERROR("DSCP match is not supported for table type L3V6"); - return false; - } - - if (attr_name == MATCH_SRC_IP || attr_name == MATCH_DST_IP) - { - SWSS_LOG_ERROR("IPv4 address match is not supported for table type L3V6"); - return false; - } - - if (attr_name == MATCH_ICMP_TYPE || attr_name == MATCH_ICMP_CODE) - { - SWSS_LOG_ERROR("ICMPv4 match is not supported for table type L3V6"); - return false; - } - - if (attr_name == MATCH_ETHER_TYPE) - { - SWSS_LOG_ERROR("Ethertype match is not supported for table type L3V6"); - return false; - } - - // TODO: For backwards compatibility, users can substitute IP_PROTOCOL for NEXT_HEADER. - // Should add a check for IP_PROTOCOL in a future release. - - return AclRule::validateAddMatch(attr_name, attr_value); -} - - -AclRuleMirror::AclRuleMirror(AclOrch *aclOrch, MirrorOrch *mirror, string rule, string table, acl_table_type_t type) : - AclRule(aclOrch, rule, table, type), - m_state(false), - m_pMirrorOrch(mirror) -{ -} - -bool AclRuleMirror::validateAddAction(string attr_name, string attr_value) -{ - SWSS_LOG_ENTER(); + SWSS_LOG_ENTER(); sai_acl_entry_attr_t action; @@ -1465,70 +1651,6 @@ bool AclRuleMirror::validateAddAction(string attr_name, string attr_value) return setAction(action, sai_acl_action_data_t{}); } -bool AclRuleMirror::validateAddMatch(string attr_name, string attr_value) -{ - if ((m_tableType == ACL_TABLE_L3 || m_tableType == ACL_TABLE_L3V6) - && attr_name == MATCH_DSCP) - { - SWSS_LOG_ERROR("DSCP match is not supported for the table of type L3"); - return false; - } - - if ((m_tableType == ACL_TABLE_MIRROR_DSCP && - aclMatchLookup.find(attr_name) != aclMatchLookup.end() && - attr_name != MATCH_DSCP)) - { - SWSS_LOG_ERROR("%s match is not supported for the table of type MIRROR_DSCP", - attr_name.c_str()); - return false; - } - - /* - * Type of Tables and Supported Match Types (Configuration) - * |---------------------------------------------------| - * | Match Type | TABLE_MIRROR | TABLE_MIRRORV6 | - * |---------------------------------------------------| - * | MATCH_SRC_IP | √ | | - * | MATCH_DST_IP | √ | | - * |---------------------------------------------------| - * | MATCH_ICMP_TYPE | √ | | - * | MATCH_ICMP_CODE | √ | | - * |---------------------------------------------------| - * | MATCH_ICMPV6_TYPE | | √ | - * | MATCH_ICMPV6_CODE | | √ | - * |---------------------------------------------------| - * | MATCH_SRC_IPV6 | | √ | - * | MATCH_DST_IPV6 | | √ | - * |---------------------------------------------------| - * | MARTCH_ETHERTYPE | √ | | - * |---------------------------------------------------| - */ - - if (m_tableType == ACL_TABLE_MIRROR && - (attr_name == MATCH_SRC_IPV6 || attr_name == MATCH_DST_IPV6 || - attr_name == MATCH_ICMPV6_TYPE || attr_name == MATCH_ICMPV6_CODE || - attr_name == MATCH_NEXT_HEADER)) - { - SWSS_LOG_ERROR("%s match is not supported for the table of type MIRROR", - attr_name.c_str()); - return false; - } - - // TODO: For backwards compatibility, users can substitute IP_PROTOCOL for NEXT_HEADER. - // This check should be expanded to include IP_PROTOCOL in a future release. - if (m_tableType == ACL_TABLE_MIRRORV6 && - (attr_name == MATCH_SRC_IP || attr_name == MATCH_DST_IP || - attr_name == MATCH_ICMP_TYPE || attr_name == MATCH_ICMP_CODE || - attr_name == MATCH_ETHER_TYPE)) - { - SWSS_LOG_ERROR("%s match is not supported for the table of type MIRRORv6", - attr_name.c_str()); - return false; - } - - return AclRule::validateAddMatch(attr_name, attr_value); -} - bool AclRuleMirror::validate() { SWSS_LOG_ENTER(); @@ -1630,6 +1752,19 @@ bool AclRuleMirror::deactivate() return true; } +bool AclRuleMirror::update(const AclRule& rule) +{ + auto mirrorRule = dynamic_cast(&rule); + if (!mirrorRule) + { + SWSS_LOG_ERROR("Cannot update mirror rule with a rule of a different type"); + return false; + } + + SWSS_LOG_ERROR("Updating mirror rule is currently not implemented"); + return false; +} + void AclRuleMirror::onUpdate(SubjectType type, void *cntx) { if (type != SUBJECT_TYPE_MIRROR_SESSION_CHANGE) @@ -1656,46 +1791,6 @@ void AclRuleMirror::onUpdate(SubjectType type, void *cntx) } } -bool AclRuleMirror::update(const AclRule& rule) -{ - auto mirrorRule = dynamic_cast(&rule); - if (!mirrorRule) - { - SWSS_LOG_ERROR("Cannot update mirror rule with a rule of a different type"); - return false; - } - - SWSS_LOG_ERROR("Updating mirror rule is currently not implemented"); - return false; -} - -AclRuleMclag::AclRuleMclag(AclOrch *aclOrch, string rule, string table, acl_table_type_t type, bool createCounter) : - AclRuleL3(aclOrch, rule, table, type, createCounter) -{ -} - -bool AclRuleMclag::validateAddMatch(string attr_name, string attr_value) -{ - if (attr_name != MATCH_IP_TYPE && attr_name != MATCH_OUT_PORTS) - { - return false; - } - - return AclRule::validateAddMatch(attr_name, attr_value); -} - -bool AclRuleMclag::validate() -{ - SWSS_LOG_ENTER(); - - if (m_matches.size() == 0) - { - return false; - } - - return true; -} - AclTable::AclTable(AclOrch *pAclOrch, string id) noexcept : m_pAclOrch(pAclOrch), id(id) { @@ -1706,20 +1801,11 @@ AclTable::AclTable(AclOrch *pAclOrch) noexcept : m_pAclOrch(pAclOrch) } -bool AclTable::validateAddType(const acl_table_type_t &value) +bool AclTable::validateAddType(const AclTableType &tableType) { SWSS_LOG_ENTER(); - if (value == ACL_TABLE_MIRROR || value == ACL_TABLE_MIRRORV6) - { - if (!m_pAclOrch->isAclMirrorTableSupported(value)) - { - SWSS_LOG_ERROR("Failed to validate type: mirror table is not supported"); - return false; - } - } - - type = value; + type = tableType; return true; } @@ -1775,318 +1861,125 @@ bool AclTable::validateAddPorts(const unordered_set &value) bool AclTable::validate() { - if (type == ACL_TABLE_CTRLPLANE) - return true; - - if (type == ACL_TABLE_UNKNOWN || stage == ACL_STAGE_UNKNOWN) - return false; - - return true; -} - -bool AclTable::create() -{ - SWSS_LOG_ENTER(); - - sai_attribute_t attr; - vector table_attrs; - vector bpoint_list; - - // PFC watch dog ACLs are only applied to port - if ((type == ACL_TABLE_PFCWD) || (type == ACL_TABLE_DROP)) + if (type.getName() == TABLE_TYPE_CTRLPLANE) { - bpoint_list = { SAI_ACL_BIND_POINT_TYPE_PORT }; + return true; } - else + + if (stage == ACL_STAGE_UNKNOWN) { - bpoint_list = { SAI_ACL_BIND_POINT_TYPE_PORT, SAI_ACL_BIND_POINT_TYPE_LAG }; + return false; } - attr.id = SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST; - attr.value.s32list.count = static_cast(bpoint_list.size()); - attr.value.s32list.list = bpoint_list.data(); - table_attrs.push_back(attr); - - if (type == ACL_TABLE_PBH) + if (m_pAclOrch->isAclActionListMandatoryOnTableCreation(stage)) { - attr.id = SAI_ACL_TABLE_ATTR_ACL_STAGE; - attr.value.s32 = SAI_ACL_STAGE_INGRESS; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_GRE_KEY; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_INNER_ETHER_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - sai_status_t status = sai_acl_api->create_acl_table(&m_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data()); - - if (status == SAI_STATUS_SUCCESS) + if (type.getActions().empty()) { - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, SAI_ACL_STAGE_INGRESS, SAI_ACL_BIND_POINT_TYPE_PORT); - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, SAI_ACL_STAGE_INGRESS, SAI_ACL_BIND_POINT_TYPE_LAG); + SWSS_LOG_ERROR("Action list for table %s is mandatory", id.c_str()); + return false; } - - return status == SAI_STATUS_SUCCESS; } - if ((type == ACL_TABLE_PFCWD) || (type == ACL_TABLE_DROP)) + for (const auto& action: type.getActions()) { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_TC; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_ACL_STAGE; - attr.value.s32 = (stage == ACL_STAGE_INGRESS) ? SAI_ACL_STAGE_INGRESS : SAI_ACL_STAGE_EGRESS; - table_attrs.push_back(attr); - - if (stage == ACL_STAGE_INGRESS) - { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IN_PORTS; - attr.value.booldata = true; - table_attrs.push_back(attr); - } - - sai_status_t status = sai_acl_api->create_acl_table(&m_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data()); - - if (status == SAI_STATUS_SUCCESS) + if (!m_pAclOrch->isAclActionSupported(stage, action)) { - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, (sai_acl_stage_t) attr.value.s32, SAI_ACL_BIND_POINT_TYPE_PORT); + SWSS_LOG_ERROR("Action %s is not supported on table %s", + sai_metadata_get_acl_action_type_name(action), id.c_str()); + return false; } - - return status == SAI_STATUS_SUCCESS; } - if (type == ACL_TABLE_MIRROR_DSCP) - { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_DSCP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_ACL_STAGE; - attr.value.s32 = (stage == ACL_STAGE_INGRESS) ? - SAI_ACL_STAGE_INGRESS : SAI_ACL_STAGE_EGRESS; - table_attrs.push_back(attr); - - sai_status_t status = sai_acl_api->create_acl_table( - &m_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data()); - - if (status == SAI_STATUS_SUCCESS) - { - gCrmOrch->incCrmAclUsedCounter( - CrmResourceType::CRM_ACL_TABLE, (sai_acl_stage_t)attr.value.s32, SAI_ACL_BIND_POINT_TYPE_PORT); - gCrmOrch->incCrmAclUsedCounter( - CrmResourceType::CRM_ACL_TABLE, (sai_acl_stage_t)attr.value.s32, SAI_ACL_BIND_POINT_TYPE_LAG); - } + return true; +} - return status == SAI_STATUS_SUCCESS; +bool AclTable::validateAclRuleMatch(sai_acl_entry_attr_t matchId, const AclRule& rule) const +{ + const auto& tableMatches = type.getMatches(); + const auto tableMatchId = AclEntryFieldToAclTableField(matchId); + const auto tableMatchIt = tableMatches.find(tableMatchId); + if (tableMatchIt == tableMatches.end()) + { + SWSS_LOG_ERROR("Match %s in rule %s is not supported by table %s", + getAttributeIdName(SAI_OBJECT_TYPE_ACL_ENTRY, matchId).c_str(), + rule.getId().c_str(), id.c_str()); + return false; } - if (type != ACL_TABLE_MIRRORV6 && type != ACL_TABLE_L3V6) + const auto& tableMatchAttrObject = tableMatchIt->second; + if (!tableMatchAttrObject->validateAclRuleMatch(rule)) { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); + SWSS_LOG_ERROR("Match %s in rule configuration %s is invalid %s", + getAttributeIdName(SAI_OBJECT_TYPE_ACL_ENTRY, matchId).c_str(), + rule.getId().c_str(), id.c_str()); + return false; } - attr.id = SAI_ACL_TABLE_ATTR_FIELD_OUTER_VLAN_ID; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - /* - * Type of Tables and Supported Match Types (ASIC database) - * |------------------------------------------------------------------| - * | | TABLE_MIRROR | TABLE_MIRROR | TABLE_MIRRORV6 | - * | Match Type |----------------------------------------------| - * | | combined | separated | - * |------------------------------------------------------------------| - * | MATCH_SRC_IP | √ | √ | | - * | MATCH_DST_IP | √ | √ | | - * |------------------------------------------------------------------| - * | MATCH_ICMP_TYPE | √ | √ | | - * | MATCH_ICMP_CODE | √ | √ | | - * |------------------------------------------------------------------| - * | MATCH_SRC_IPV6 | √ | | √ | - * | MATCH_DST_IPV6 | √ | | √ | - * |------------------------------------------------------------------| - * | MATCH_ICMPV6_TYPE | √ | | √ | - * | MATCH_ICMPV6_CODE | √ | | √ | - * |------------------------------------------------------------------| - * | MATCH_IP_PROTOCOL | √ | √ | | - * | MATCH_NEXT_HEADER | √ | | √ | - * | -----------------------------------------------------------------| - * | MATCH_ETHERTYPE | √ | √ | | - * |------------------------------------------------------------------| - * | MATCH_IN_PORTS | √ | √ | | - * |------------------------------------------------------------------| - */ + return true; +} - // FIXME: This section has become hard to maintain and should be refactored. - if (type == ACL_TABLE_MIRROR) +bool AclTable::validateAclRuleAction(sai_acl_entry_attr_t actionId, const AclRule& rule) const +{ + // This means ACL table can hold rules with any action. + if (!type.getActions().empty()) { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_SRC_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_DST_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ICMP_CODE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IN_PORTS; - attr.value.booldata = true; - table_attrs.push_back(attr); - - // If the switch supports v6 and requires one single table - if (m_pAclOrch->m_mirrorTableCapabilities[ACL_TABLE_MIRRORV6] && - m_pAclOrch->m_isCombinedMirrorV6Table) + auto action = AclEntryActionToAclAction(actionId); + if (!type.getActions().count(action)) { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_CODE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER; - attr.value.booldata = true; - table_attrs.push_back(attr); + SWSS_LOG_ERROR("Action %s is not supported on table %s", + sai_metadata_get_acl_action_type_name(action), id.c_str()); + return false; } } - else if (type == ACL_TABLE_L3V6 || type == ACL_TABLE_MIRRORV6) // v6 only - { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6; - attr.value.booldata = true; - table_attrs.push_back(attr); - attr.id = SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_CODE; - attr.value.booldata = true; - table_attrs.push_back(attr); + return true; +} - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER; - attr.value.booldata = true; - table_attrs.push_back(attr); - } - else // v4 only - { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_SRC_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); +bool AclTable::create() +{ + SWSS_LOG_ENTER(); - attr.id = SAI_ACL_TABLE_ATTR_FIELD_DST_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); + sai_attribute_t attr; + vector table_attrs; + vector action_types_list {type.getActions().begin(), type.getActions().end()}; + vector bpoint_list {type.getBindPointTypes().begin(), type.getBindPointTypes().end()}; - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); + attr.id = SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST; + attr.value.s32list.count = static_cast(bpoint_list.size()); + attr.value.s32list.list = bpoint_list.data(); + table_attrs.push_back(attr); - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ICMP_CODE; - attr.value.booldata = true; - table_attrs.push_back(attr); + for (const auto& matchPair: type.getMatches()) + { + table_attrs.push_back(matchPair.second->toSaiAttribute()); + } - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL; - attr.value.booldata = true; + if (!action_types_list.empty()) + { + attr.id= SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST; + attr.value.s32list.count = static_cast(action_types_list.size()); + attr.value.s32list.list = action_types_list.data(); table_attrs.push_back(attr); } - attr.id = SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS; - attr.value.booldata = true; - table_attrs.push_back(attr); - - int32_t range_types_list[] = { SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE, SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE }; - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ACL_RANGE_TYPE; - attr.value.s32list.count = (uint32_t)(sizeof(range_types_list) / sizeof(range_types_list[0])); - attr.value.s32list.list = range_types_list; - table_attrs.push_back(attr); - sai_acl_stage_t acl_stage; attr.id = SAI_ACL_TABLE_ATTR_ACL_STAGE; acl_stage = (stage == ACL_STAGE_INGRESS) ? SAI_ACL_STAGE_INGRESS : SAI_ACL_STAGE_EGRESS; attr.value.s32 = acl_stage; table_attrs.push_back(attr); - if (type == ACL_TABLE_MIRROR || type == ACL_TABLE_MIRRORV6) - { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_DSCP; - attr.value.booldata = true; - table_attrs.push_back(attr); - } - - if (type == ACL_TABLE_MCLAG) + sai_status_t status = sai_acl_api->create_acl_table(&m_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data()); + if (status != SAI_STATUS_SUCCESS) { - attr.id = SAI_ACL_TABLE_ATTR_FIELD_OUT_PORTS; - attr.value.booldata = true; - table_attrs.push_back(attr); + return false; } - sai_status_t status = sai_acl_api->create_acl_table(&m_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data()); - - if (status == SAI_STATUS_SUCCESS) + for (const auto& bpointType: type.getBindPointTypes()) { - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, acl_stage, SAI_ACL_BIND_POINT_TYPE_PORT); - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, acl_stage, SAI_ACL_BIND_POINT_TYPE_LAG); + gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, acl_stage, bpointType); } - return status == SAI_STATUS_SUCCESS; + return true; } void AclTable::onUpdate(SubjectType type, void *cntx) @@ -2326,8 +2219,8 @@ bool AclTable::clear() return true; } -AclRuleDTelFlowWatchListEntry::AclRuleDTelFlowWatchListEntry(AclOrch *aclOrch, DTelOrch *dtel, string rule, string table, acl_table_type_t type) : - AclRule(aclOrch, rule, table, type), +AclRuleDTelFlowWatchListEntry::AclRuleDTelFlowWatchListEntry(AclOrch *aclOrch, DTelOrch *dtel, string rule, string table) : + AclRule(aclOrch, rule, table), m_pDTelOrch(dtel) { } @@ -2565,8 +2458,8 @@ bool AclRuleDTelFlowWatchListEntry::update(const AclRule& rule) return false; } -AclRuleDTelDropWatchListEntry::AclRuleDTelDropWatchListEntry(AclOrch *aclOrch, DTelOrch *dtel, string rule, string table, acl_table_type_t type) : - AclRule(aclOrch, rule, table, type), +AclRuleDTelDropWatchListEntry::AclRuleDTelDropWatchListEntry(AclOrch *aclOrch, DTelOrch *dtel, string rule, string table) : + AclRule(aclOrch, rule, table), m_pDTelOrch(dtel) { } @@ -2762,24 +2655,24 @@ void AclOrch::init(vector& connectors, PortsOrch *portOrch, Mirr { m_mirrorTableCapabilities = { - { ACL_TABLE_MIRROR, true }, - { ACL_TABLE_MIRRORV6, true }, + { TABLE_TYPE_MIRROR, true }, + { TABLE_TYPE_MIRRORV6, true }, }; } else { m_mirrorTableCapabilities = { - { ACL_TABLE_MIRROR, true }, - { ACL_TABLE_MIRRORV6, false }, + { TABLE_TYPE_MIRROR, true }, + { TABLE_TYPE_MIRRORV6, false }, }; } SWSS_LOG_NOTICE("%s switch capability:", platform.c_str()); - SWSS_LOG_NOTICE(" ACL_TABLE_MIRROR: %s", - m_mirrorTableCapabilities[ACL_TABLE_MIRROR] ? "yes" : "no"); - SWSS_LOG_NOTICE(" ACL_TABLE_MIRRORV6: %s", - m_mirrorTableCapabilities[ACL_TABLE_MIRRORV6] ? "yes" : "no"); + SWSS_LOG_NOTICE(" TABLE_TYPE_MIRROR: %s", + m_mirrorTableCapabilities[TABLE_TYPE_MIRROR] ? "yes" : "no"); + SWSS_LOG_NOTICE(" TABLE_TYPE_MIRRORV6: %s", + m_mirrorTableCapabilities[TABLE_TYPE_MIRRORV6] ? "yes" : "no"); // In Mellanox platform, V4 and V6 rules are stored in different tables if (platform == MLNX_PLATFORM_SUBSTRING || @@ -2793,57 +2686,239 @@ void AclOrch::init(vector& connectors, PortsOrch *portOrch, Mirr } - // Store the capabilities in state database - // TODO: Move this part of the code into syncd - vector fvVector; - for (auto const& it : m_mirrorTableCapabilities) + // Store the capabilities in state database + // TODO: Move this part of the code into syncd + vector fvVector; + for (auto const& it : m_mirrorTableCapabilities) + { + string value = it.second ? "true" : "false"; + if (it.first == TABLE_TYPE_MIRROR) + { + fvVector.emplace_back(TABLE_TYPE_MIRROR, value); + } + else if (it.first == TABLE_TYPE_MIRRORV6) + { + fvVector.emplace_back(TABLE_TYPE_MIRRORV6, value); + } + else + { + // ignore + } + } + m_switchOrch->set_switch_capability(fvVector); + + sai_attribute_t attrs[2]; + attrs[0].id = SAI_SWITCH_ATTR_ACL_ENTRY_MINIMUM_PRIORITY; + attrs[1].id = SAI_SWITCH_ATTR_ACL_ENTRY_MAXIMUM_PRIORITY; + + sai_status_t status = sai_switch_api->get_switch_attribute(gSwitchId, 2, attrs); + if (status == SAI_STATUS_SUCCESS) + { + SWSS_LOG_NOTICE("Get ACL entry priority values, min: %u, max: %u", attrs[0].value.u32, attrs[1].value.u32); + AclRule::setRulePriorities(attrs[0].value.u32, attrs[1].value.u32); + } + else + { + SWSS_LOG_ERROR("Failed to get ACL entry priority min/max values, rv:%d", status); + task_process_status handle_status = handleSaiGetStatus(SAI_API_SWITCH, status); + if (handle_status != task_process_status::task_success) + { + throw "AclOrch initialization failure"; + } + } + + queryAclActionCapability(); + + for (auto stage: {ACL_STAGE_INGRESS, ACL_STAGE_EGRESS}) + { + m_mirrorTableId[stage] = ""; + m_mirrorV6TableId[stage] = ""; + } + + initDefaultTableTypes(); + + // Attach observers + m_mirrorOrch->attach(this); + gPortsOrch->attach(this); +} + +void AclOrch::initDefaultTableTypes() +{ + SWSS_LOG_ENTER(); + + AclTableTypeBuilder builder; + + addAclTableType( + builder.withName(TABLE_TYPE_L3) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .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_ACL_IP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMP_CODE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS)) + .withMatch(make_shared(set{ + {SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE, SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE}})) + .build() + ); + + addAclTableType( + builder.withName(TABLE_TYPE_L3V6) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_OUTER_VLAN_ID)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_CODE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS)) + .withMatch(make_shared(set{ + {SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE, SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE}})) + .build() + ); + + addAclTableType( + builder.withName(TABLE_TYPE_MCLAG) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .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_ACL_IP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMP_CODE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_OUT_PORTS)) + .withMatch(make_shared(set{ + {SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE, SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE}})) + .build() + ); + + addAclTableType( + builder.withName(TABLE_TYPE_PFCWD) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TC)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IN_PORTS)) + .build() + ); + + addAclTableType( + builder.withName(TABLE_TYPE_DROP) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TC)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IN_PORTS)) + .build() + ); + + + /* + * Type of Tables and Supported Match Types (ASIC database) + * |------------------------------------------------------------------| + * | | TABLE_MIRROR | TABLE_MIRROR | TABLE_MIRRORV6 | + * | Match Type |----------------------------------------------| + * | | combined | separated | + * |------------------------------------------------------------------| + * | MATCH_SRC_IP | √ | √ | | + * | MATCH_DST_IP | √ | √ | | + * |------------------------------------------------------------------| + * | MATCH_ICMP_TYPE | √ | √ | | + * | MATCH_ICMP_CODE | √ | √ | | + * |------------------------------------------------------------------| + * | MATCH_SRC_IPV6 | √ | | √ | + * | MATCH_DST_IPV6 | √ | | √ | + * |------------------------------------------------------------------| + * | MATCH_ICMPV6_TYPE | √ | | √ | + * | MATCH_ICMPV6_CODE | √ | | √ | + * |------------------------------------------------------------------| + * | MATCH_IP_PROTOCOL | √ | √ | | + * | MATCH_NEXT_HEADER | √ | | √ | + * | -----------------------------------------------------------------| + * | MATCH_ETHERTYPE | √ | √ | | + * |------------------------------------------------------------------| + * | MATCH_IN_PORTS | √ | √ | | + * |------------------------------------------------------------------| + */ + + if (isAclMirrorV4Supported()) { - string value = it.second ? "true" : "false"; - switch (it.first) - { - case ACL_TABLE_MIRROR: - fvVector.emplace_back(TABLE_TYPE_MIRROR, value); - break; - case ACL_TABLE_MIRRORV6: - fvVector.emplace_back(TABLE_TYPE_MIRRORV6, value); - break; - default: - break; - } - } - m_switchOrch->set_switch_capability(fvVector); - - sai_attribute_t attrs[2]; - attrs[0].id = SAI_SWITCH_ATTR_ACL_ENTRY_MINIMUM_PRIORITY; - attrs[1].id = SAI_SWITCH_ATTR_ACL_ENTRY_MAXIMUM_PRIORITY; + addAclTableType( + builder.withName(TABLE_TYPE_MIRROR_DSCP) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DSCP)) + .build() + ); - sai_status_t status = sai_switch_api->get_switch_attribute(gSwitchId, 2, attrs); - if (status == SAI_STATUS_SUCCESS) - { - SWSS_LOG_NOTICE("Get ACL entry priority values, min: %u, max: %u", attrs[0].value.u32, attrs[1].value.u32); - AclRule::setRulePriorities(attrs[0].value.u32, attrs[1].value.u32); - } - else - { - SWSS_LOG_ERROR("Failed to get ACL entry priority min/max values, rv:%d", status); - task_process_status handle_status = handleSaiGetStatus(SAI_API_SWITCH, status); - if (handle_status != task_process_status::task_success) + builder.withName(TABLE_TYPE_MIRROR) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .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_ACL_IP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMP_CODE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IN_PORTS)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DSCP)) + .withMatch(make_shared(set{ + {SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE, SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE}})); + + if (isAclMirrorV6Supported() && isCombinedMirrorV6Table()) { - throw "AclOrch initialization failure"; + builder + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_CODE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER)); } + addAclTableType(builder.build()); + } + + if (isAclMirrorV6Supported()) + { + addAclTableType( + builder.withName(TABLE_TYPE_MIRRORV6) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_OUTER_VLAN_ID)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ACL_IP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_CODE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMPV6_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DSCP)) + .withMatch(make_shared(set{ + {SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE, SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE}})) + .build() + ); } - queryAclActionCapability(); - - for (auto stage: {ACL_STAGE_INGRESS, ACL_STAGE_EGRESS}) - { - m_mirrorTableId[stage] = ""; - m_mirrorV6TableId[stage] = ""; - } - - // Attach observers - m_mirrorOrch->attach(this); - gPortsOrch->attach(this); + // Placeholder for control plane tables + addAclTableType(builder.withName(TABLE_TYPE_CTRLPLANE).build()); } void AclOrch::queryAclActionCapability() @@ -2877,12 +2952,15 @@ void AclOrch::queryAclActionCapability() SWSS_LOG_INFO("Supported %s action count %d:", stage_str, attr.value.aclcapability.action_list.count); + auto& capabilities = m_aclCapabilities[stage]; + for (size_t i = 0; i < static_cast(attr.value.aclcapability.action_list.count); i++) { auto action = static_cast(action_list[i]); - m_aclCapabilities[stage].insert(action); + capabilities.actionList.insert(action); SWSS_LOG_INFO(" %s", sai_serialize_enum(action, &sai_metadata_enum_sai_acl_action_type_t).c_str()); } + capabilities.isActionListMandatoryOnTableCreation = attr.value.aclcapability.is_action_list_mandatory; } else { @@ -2930,16 +3008,18 @@ void AclOrch::putAclActionCapabilityInDB(acl_stage_type_t stage) auto stage_str = (stage == ACL_STAGE_INGRESS ? STAGE_INGRESS : STAGE_EGRESS); auto field = std::string("ACL_ACTIONS") + '|' + stage_str; - auto& acl_action_set = m_aclCapabilities[stage]; + auto& capabilities = m_aclCapabilities[stage]; + auto& acl_action_set = capabilities.actionList; string delimiter; ostringstream acl_action_value_stream; + ostringstream is_action_list_mandatory_stream; for (const auto& action_map: {aclL3ActionLookup, aclMirrorStageLookup, aclDTelActionLookup}) { for (const auto& it: action_map) { - auto saiAction = getAclActionFromAclEntry(it.second); + auto saiAction = AclEntryActionToAclAction(it.second); if (acl_action_set.find(saiAction) != acl_action_set.cend()) { acl_action_value_stream << delimiter << it.first; @@ -2948,8 +3028,11 @@ void AclOrch::putAclActionCapabilityInDB(acl_stage_type_t stage) } } - fvVector.emplace_back(field, acl_action_value_stream.str()); - m_switchOrch->set_switch_capability(fvVector); + is_action_list_mandatory_stream << boolalpha << capabilities.isActionListMandatoryOnTableCreation; + + fvVector.emplace_back(STATE_DB_ACL_ACTION_FIELD_IS_ACTION_LIST_MANDATORY, is_action_list_mandatory_stream.str()); + fvVector.emplace_back(STATE_DB_ACL_ACTION_FIELD_ACTION_LIST, acl_action_value_stream.str()); + m_aclStageCapabilityTable.set(stage_str, fvVector); } void AclOrch::initDefaultAclActionCapabilities(acl_stage_type_t stage) @@ -2958,9 +3041,9 @@ void AclOrch::initDefaultAclActionCapabilities(acl_stage_type_t stage) SWSS_LOG_INFO("Assumed %s %zu actions to be supported:", stage == ACL_STAGE_INGRESS ? STAGE_INGRESS : STAGE_EGRESS, - m_aclCapabilities[stage].size()); + m_aclCapabilities[stage].actionList.size()); - for (auto action: m_aclCapabilities[stage]) + for (auto action: m_aclCapabilities[stage].actionList) { SWSS_LOG_INFO(" %s", sai_serialize_enum(action, &sai_metadata_enum_sai_acl_action_type_t).c_str()); } @@ -2975,7 +3058,7 @@ void AclOrch::queryAclActionAttrEnumValues(const string &action_name, { vector fvVector; auto acl_attr = ruleAttrLookupMap.at(action_name); - auto acl_action = getAclActionFromAclEntry(acl_attr); + auto acl_action = AclEntryActionToAclAction(acl_attr); /* if the action is not supported then no need to do secondary query for * supported values @@ -3054,19 +3137,10 @@ void AclOrch::queryAclActionAttrEnumValues(const string &action_name, m_switchOrch->set_switch_capability(fvVector); } -sai_acl_action_type_t AclOrch::getAclActionFromAclEntry(sai_acl_entry_attr_t attr) -{ - if (attr < SAI_ACL_ENTRY_ATTR_ACTION_START || attr > SAI_ACL_ENTRY_ATTR_ACTION_END) - { - SWSS_LOG_THROW("Invalid ACL entry attribute passed in: %d", attr); - } - - return static_cast(attr - SAI_ACL_ENTRY_ATTR_ACTION_START); -}; - -AclOrch::AclOrch(vector& connectors, SwitchOrch *switchOrch, +AclOrch::AclOrch(vector& connectors, DBConnector* stateDb, SwitchOrch *switchOrch, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch, DTelOrch *dtelOrch) : Orch(connectors), + m_aclStageCapabilityTable(stateDb, STATE_ACL_STAGE_CAPABILITY_TABLE_NAME), m_switchOrch(switchOrch), m_mirrorOrch(mirrorOrch), m_neighOrch(neighOrch), @@ -3150,6 +3224,10 @@ void AclOrch::doTask(Consumer &consumer) { doAclRuleTask(consumer); } + else if (table_name == CFG_ACL_TABLE_TYPE_TABLE_NAME || table_name == APP_ACL_TABLE_TYPE_TABLE_NAME) + { + doAclTableTypeTask(consumer); + } else { SWSS_LOG_ERROR("Invalid table %s", table_name.c_str()); @@ -3304,7 +3382,7 @@ bool AclOrch::addAclTable(AclTable &newTable) SWSS_LOG_ENTER(); string table_id = newTable.id; - if (newTable.type == ACL_TABLE_CTRLPLANE) + if (newTable.type.getName() == TABLE_TYPE_CTRLPLANE) { m_ctrlAclTables.emplace(table_id, newTable); SWSS_LOG_NOTICE("Created control plane ACL table %s", newTable.id.c_str()); @@ -3329,15 +3407,15 @@ bool AclOrch::addAclTable(AclTable &newTable) // If ACL table is new, check for the existence of current mirror tables // Note: only one table per mirror type can be created auto table_type = newTable.type; - if (table_type == ACL_TABLE_MIRROR || table_type == ACL_TABLE_MIRRORV6) + if (table_type.getName() == TABLE_TYPE_MIRROR || table_type.getName() == TABLE_TYPE_MIRRORV6) { string mirror_type; - if (table_type == ACL_TABLE_MIRROR && !m_mirrorTableId[table_stage].empty()) + if (table_type.getName() == TABLE_TYPE_MIRROR && !m_mirrorTableId[table_stage].empty()) { mirror_type = TABLE_TYPE_MIRROR; } - if (table_type == ACL_TABLE_MIRRORV6 && !m_mirrorV6TableId[table_stage].empty()) + if (table_type.getName() == TABLE_TYPE_MIRRORV6 && !m_mirrorV6TableId[table_stage].empty()) { mirror_type = TABLE_TYPE_MIRRORV6; } @@ -3355,7 +3433,7 @@ bool AclOrch::addAclTable(AclTable &newTable) } // Check if a separate mirror table is needed or not based on the platform - if (newTable.type == ACL_TABLE_MIRROR || newTable.type == ACL_TABLE_MIRRORV6) + if (newTable.type.getName() == TABLE_TYPE_MIRROR || newTable.type.getName() == TABLE_TYPE_MIRRORV6) { if (m_isCombinedMirrorV6Table && (!m_mirrorTableId[table_stage].empty() || @@ -3389,11 +3467,11 @@ bool AclOrch::addAclTable(AclTable &newTable) newTable.id.c_str(), table_oid); // Mark the existence of the mirror table - if (newTable.type == ACL_TABLE_MIRROR) + if (newTable.type.getName() == TABLE_TYPE_MIRROR) { m_mirrorTableId[table_stage] = table_id; } - else if (newTable.type == ACL_TABLE_MIRRORV6) + else if (newTable.type.getName() == TABLE_TYPE_MIRRORV6) { m_mirrorV6TableId[table_stage] = table_id; } @@ -3428,11 +3506,9 @@ bool AclOrch::removeAclTable(string table_id) auto type = m_AclTables[table_oid].type; sai_acl_stage_t sai_stage = (stage == ACL_STAGE_INGRESS) ? SAI_ACL_STAGE_INGRESS : SAI_ACL_STAGE_EGRESS; - gCrmOrch->decCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, sai_stage, SAI_ACL_BIND_POINT_TYPE_PORT, table_oid); - - if (type != ACL_TABLE_PFCWD) + for (const auto& bpointType: type.getBindPointTypes()) { - gCrmOrch->decCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, sai_stage, SAI_ACL_BIND_POINT_TYPE_LAG, table_oid); + gCrmOrch->decCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, sai_stage, bpointType, table_oid); } SWSS_LOG_NOTICE("Successfully deleted ACL table %s", table_id.c_str()); @@ -3467,6 +3543,44 @@ bool AclOrch::removeAclTable(string table_id) } } +bool AclOrch::addAclTableType(const AclTableType& tableType) +{ + SWSS_LOG_ENTER(); + + if (tableType.getName().empty()) + { + SWSS_LOG_ERROR("Received table type without a name"); + return false; + } + + if (m_AclTableTypes.find(tableType.getName()) != m_AclTableTypes.end()) + { + SWSS_LOG_ERROR("Table type %s already exists", tableType.getName().c_str()); + return false; + } + + m_AclTableTypes.emplace(tableType.getName(), tableType); + return true; +} + +bool AclOrch::removeAclTableType(const string& tableTypeName) +{ + // It is Ok to remove table type that is in use by AclTable. + // AclTable holds a copy of AclTableType and there is no + // SAI object associated with AclTableType. + // So it is no harm to remove it without validation. + // The upper layer can although ensure that + // user does not remove table type that is referenced + // by an ACL table. + if (!m_AclTableTypes.erase(tableTypeName)) + { + SWSS_LOG_ERROR("Unknown table type %s", tableTypeName.c_str()); + return false; + } + + return true; +} + bool AclOrch::addAclRule(shared_ptr newRule, string table_id) { sai_object_id_t table_oid = getTableById(table_id); @@ -3683,7 +3797,7 @@ bool AclOrch::isCombinedMirrorV6Table() return m_isCombinedMirrorV6Table; } -bool AclOrch::isAclMirrorTableSupported(acl_table_type_t type) const +bool AclOrch::isAclMirrorTableSupported(string type) const { const auto &cit = m_mirrorTableCapabilities.find(type); if (cit == m_mirrorTableCapabilities.cend()) @@ -3694,6 +3808,26 @@ bool AclOrch::isAclMirrorTableSupported(acl_table_type_t type) const return cit->second; } +bool AclOrch::isAclMirrorV4Supported() const +{ + return isAclMirrorTableSupported(TABLE_TYPE_MIRROR); +} + +bool AclOrch::isAclMirrorV6Supported() const +{ + return isAclMirrorTableSupported(TABLE_TYPE_MIRRORV6); +} + +bool AclOrch::isAclActionListMandatoryOnTableCreation(acl_stage_type_t stage) const +{ + const auto& it = m_aclCapabilities.find(stage); + if (it == m_aclCapabilities.cend()) + { + return false; + } + return it->second.isActionListMandatoryOnTableCreation; +} + bool AclOrch::isAclActionSupported(acl_stage_type_t stage, sai_acl_action_type_t action) const { const auto& it = m_aclCapabilities.find(stage); @@ -3701,7 +3835,8 @@ bool AclOrch::isAclActionSupported(acl_stage_type_t stage, sai_acl_action_type_t { return false; } - return it->second.find(action) != it->second.cend(); + const auto& actionCapability = it->second; + return actionCapability.actionList.find(action) != actionCapability.actionList.cend(); } bool AclOrch::isAclActionEnumValueSupported(sai_acl_action_type_t action, sai_acl_action_parameter_t param) const @@ -3732,6 +3867,7 @@ void AclOrch::doAclTableTask(Consumer &consumer) if (op == SET_COMMAND) { AclTable newTable(this); + string tableTypeName; bool bAllAttributesOk = true; newTable.id = table_id; @@ -3749,7 +3885,7 @@ void AclOrch::doAclTableTask(Consumer &consumer) } else if (attr_name == ACL_TABLE_TYPE) { - if (!processAclTableType(attr_value, newTable.type)) + if (!processAclTableType(attr_value, tableTypeName)) { SWSS_LOG_ERROR("Failed to process ACL table %s type", table_id.c_str()); @@ -3790,6 +3926,15 @@ void AclOrch::doAclTableTask(Consumer &consumer) } } + auto tableType = getAclTableType(tableTypeName); + if (!tableType) + { + it++; + continue; + } + + newTable.validateAddType(*tableType); + // validate and create/update ACL Table if (bAllAttributesOk && newTable.validate()) { @@ -3799,7 +3944,7 @@ void AclOrch::doAclTableTask(Consumer &consumer) sai_object_id_t table_oid = getTableById(table_id); if (table_oid != SAI_NULL_OBJECT_ID && - !isAclTableTypeUpdated(newTable.type, + !isAclTableTypeUpdated(newTable.type.getName(), m_AclTables[table_oid]) && !isAclTableStageUpdated(newTable.stage, m_AclTables[table_oid])) @@ -3880,8 +4025,7 @@ void AclOrch::doAclRuleTask(Consumer &consumer) sai_object_id_t table_oid = getTableById(table_id); /* ACL table is not yet created or ACL table is a control plane table */ - /* TODO: Remove ACL_TABLE_UNKNOWN as a table with this type cannot be successfully created */ - if (table_oid == SAI_NULL_OBJECT_ID || m_AclTables[table_oid].type == ACL_TABLE_UNKNOWN) + if (table_oid == SAI_NULL_OBJECT_ID) { /* Skip the control plane rules */ @@ -3897,17 +4041,17 @@ void AclOrch::doAclRuleTask(Consumer &consumer) continue; } - auto type = m_AclTables[table_oid].type; + auto type = m_AclTables[table_oid].type.getName(); auto stage = m_AclTables[table_oid].stage; - if (type == ACL_TABLE_MIRROR || type == ACL_TABLE_MIRRORV6) + if (type == TABLE_TYPE_MIRROR || type == TABLE_TYPE_MIRRORV6) { - type = table_id == m_mirrorTableId[stage] ? ACL_TABLE_MIRROR : ACL_TABLE_MIRRORV6; + type = table_id == m_mirrorTableId[stage] ? TABLE_TYPE_MIRROR : TABLE_TYPE_MIRRORV6; } try { - newRule = AclRule::makeShared(type, this, m_mirrorOrch, m_dTelOrch, rule_id, table_id, t); + newRule = AclRule::makeShared(this, m_mirrorOrch, m_dTelOrch, rule_id, table_id, t); } catch (exception &e) { @@ -3955,7 +4099,7 @@ void AclOrch::doAclRuleTask(Consumer &consumer) if (bHasTCPFlag && !bHasIPProtocol) { string attr_name; - if (type == ACL_TABLE_MIRRORV6 || type == ACL_TABLE_L3V6) + if (type == TABLE_TYPE_MIRRORV6 || type == TABLE_TYPE_L3V6) { attr_name = MATCH_NEXT_HEADER; } @@ -4004,6 +4148,42 @@ void AclOrch::doAclRuleTask(Consumer &consumer) } } +void AclOrch::doAclTableTypeTask(Consumer &consumer) +{ + SWSS_LOG_ENTER(); + + auto it = consumer.m_toSync.begin(); + while (it != consumer.m_toSync.end()) + { + auto keyOpFieldValues = it->second; + auto key = kfvKey(keyOpFieldValues); + auto op = kfvOp(keyOpFieldValues); + + if (op == SET_COMMAND) + { + AclTableTypeBuilder builder; + if (!AclTableTypeParser().parse(key, kfvFieldsValues(keyOpFieldValues), builder)) + { + SWSS_LOG_ERROR("Failed to parse ACL table type configuration %s", key.c_str()); + it = consumer.m_toSync.erase(it); + continue; + } + + addAclTableType(builder.build()); + } + else if (op == DEL_COMMAND) + { + removeAclTableType(key); + } + else + { + SWSS_LOG_ERROR("Unknown operation type %s", op.c_str()); + } + + it = consumer.m_toSync.erase(it); + } +} + bool AclOrch::processAclTablePorts(string portList, AclTable &aclTable) { SWSS_LOG_ENTER(); @@ -4037,39 +4217,26 @@ bool AclOrch::processAclTablePorts(string portList, AclTable &aclTable) return true; } -bool AclOrch::isAclTableTypeUpdated(acl_table_type_t table_type, AclTable &t) +bool AclOrch::isAclTableTypeUpdated(string table_type, AclTable &t) { - if (m_isCombinedMirrorV6Table && (table_type == ACL_TABLE_MIRROR || table_type == ACL_TABLE_MIRRORV6)) + if (m_isCombinedMirrorV6Table && (table_type == TABLE_TYPE_MIRROR || table_type == TABLE_TYPE_MIRRORV6)) { - // ACL_TABLE_MIRRORV6 and ACL_TABLE_MIRROR should be treated as same type in combined scenario - return !(t.type == ACL_TABLE_MIRROR || t.type == ACL_TABLE_MIRRORV6); + // TABLE_TYPE_MIRRORV6 and TABLE_TYPE_MIRROR should be treated as same type in combined scenario + return !(t.type.getName() == TABLE_TYPE_MIRROR || t.type.getName() == TABLE_TYPE_MIRRORV6); } - return (table_type != t.type); + return (table_type != t.type.getName()); } -bool AclOrch::processAclTableType(string type, acl_table_type_t &table_type) +bool AclOrch::processAclTableType(string type, string &out_table_type) { SWSS_LOG_ENTER(); - auto iter = aclTableTypeLookUp.find(to_upper(type)); - - if (iter == aclTableTypeLookUp.end()) + if (type.empty()) { return false; } - table_type = iter->second; - - // Mirror table check procedure - if (table_type == ACL_TABLE_MIRROR || table_type == ACL_TABLE_MIRRORV6) - { - // Check the switch capability - if (!m_mirrorTableCapabilities[table_type]) - { - SWSS_LOG_ERROR("Mirror table type %s is not supported", type.c_str()); - return false; - } - } + out_table_type = type; return true; } @@ -4096,6 +4263,18 @@ bool AclOrch::processAclTableStage(string stage, acl_stage_type_t &acl_stage) return true; } +const AclTableType* AclOrch::getAclTableType(const string& tableTypeName) const +{ + auto it = m_AclTableTypes.find(to_upper(tableTypeName)); + if (it == m_AclTableTypes.end()) + { + SWSS_LOG_INFO("Failed to find ACL table type %s", tableTypeName.c_str()); + return nullptr; + } + + return &it->second; +} + sai_object_id_t AclOrch::getTableById(string table_id) { SWSS_LOG_ENTER(); @@ -4197,220 +4376,61 @@ sai_status_t AclOrch::bindAclTable(AclTable &aclTable, bool bind) return status; } -sai_status_t AclOrch::createDTelWatchListTables() +void AclOrch::createDTelWatchListTables() { SWSS_LOG_ENTER(); - AclTable flowWLTable, dropWLTable; - sai_object_id_t table_oid; - - sai_status_t status; - sai_attribute_t attr; - vector table_attrs; - - /* Create Flow watchlist ACL table */ - - flowWLTable.id = TABLE_TYPE_DTEL_FLOW_WATCHLIST; - flowWLTable.type = ACL_TABLE_DTEL_FLOW_WATCHLIST; - flowWLTable.description = "Dataplane Telemetry Flow Watchlist table"; - - attr.id = SAI_ACL_TABLE_ATTR_ACL_STAGE; - attr.value.s32 = SAI_ACL_STAGE_INGRESS; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST; - vector bpoint_list; - bpoint_list.push_back(SAI_ACL_BIND_POINT_TYPE_SWITCH); - attr.value.s32list.count = 1; - attr.value.s32list.list = bpoint_list.data(); - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_SRC_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_DST_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_TUNNEL_VNI; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_INNER_ETHER_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_INNER_SRC_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_INNER_DST_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST; - int32_t acl_action_list[4]; - acl_action_list[0] = SAI_ACL_ACTION_TYPE_ACL_DTEL_FLOW_OP; - acl_action_list[1] = SAI_ACL_ACTION_TYPE_DTEL_INT_SESSION; - acl_action_list[2] = SAI_ACL_ACTION_TYPE_DTEL_REPORT_ALL_PACKETS; - acl_action_list[3] = SAI_ACL_ACTION_TYPE_DTEL_FLOW_SAMPLE_PERCENT; - attr.value.s32list.count = 4; - attr.value.s32list.list = acl_action_list; - table_attrs.push_back(attr); - - status = sai_acl_api->create_acl_table(&table_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data()); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to create table %s", flowWLTable.description.c_str()); - if (handleSaiCreateStatus(SAI_API_ACL, status) != task_success) - { - return status; - } - } - - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, SAI_ACL_STAGE_INGRESS, SAI_ACL_BIND_POINT_TYPE_SWITCH); - m_AclTables[table_oid] = flowWLTable; - SWSS_LOG_INFO("Successfully created ACL table %s, oid: %" PRIx64, flowWLTable.description.c_str(), table_oid); - - /* Create Drop watchlist ACL table */ - - table_attrs.clear(); - - dropWLTable.id = TABLE_TYPE_DTEL_DROP_WATCHLIST; - dropWLTable.type = ACL_TABLE_DTEL_DROP_WATCHLIST; - dropWLTable.description = "Dataplane Telemetry Drop Watchlist table"; - - attr.id = SAI_ACL_TABLE_ATTR_ACL_STAGE; - attr.value.s32 = SAI_ACL_STAGE_INGRESS; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST; - bpoint_list.clear(); - bpoint_list.push_back(SAI_ACL_BIND_POINT_TYPE_SWITCH); - attr.value.s32list.count = 1; - attr.value.s32list.list = bpoint_list.data(); - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_SRC_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_DST_IP; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL; - attr.value.booldata = true; - table_attrs.push_back(attr); - - attr.id = SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST; - acl_action_list[0] = SAI_ACL_ACTION_TYPE_DTEL_DROP_REPORT_ENABLE; - acl_action_list[1] = SAI_ACL_ACTION_TYPE_DTEL_TAIL_DROP_REPORT_ENABLE; - attr.value.s32list.count = 2; - attr.value.s32list.list = acl_action_list; - table_attrs.push_back(attr); - - status = sai_acl_api->create_acl_table(&table_oid, gSwitchId, (uint32_t)table_attrs.size(), table_attrs.data()); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to create table %s", dropWLTable.description.c_str()); - if (handleSaiCreateStatus(SAI_API_ACL, status) != task_success) - { - return status; - } - } - - gCrmOrch->incCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, SAI_ACL_STAGE_INGRESS, SAI_ACL_BIND_POINT_TYPE_SWITCH); - m_AclTables[table_oid] = dropWLTable; - SWSS_LOG_INFO("Successfully created ACL table %s, oid: %" PRIx64, dropWLTable.description.c_str(), table_oid); + AclTableTypeBuilder builder; + + AclTable flowWLTable(this, TABLE_TYPE_DTEL_FLOW_WATCHLIST); + AclTable dropWLTable(this, TABLE_TYPE_DTEL_DROP_WATCHLIST); + + flowWLTable.validateAddStage(ACL_STAGE_INGRESS); + flowWLTable.validateAddType(builder + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_SWITCH) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TUNNEL_VNI)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_INNER_ETHER_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_INNER_SRC_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_INNER_DST_IP)) + .withAction(SAI_ACL_ACTION_TYPE_ACL_DTEL_FLOW_OP) + .withAction(SAI_ACL_ACTION_TYPE_DTEL_INT_SESSION) + .withAction(SAI_ACL_ACTION_TYPE_DTEL_REPORT_ALL_PACKETS) + .withAction(SAI_ACL_ACTION_TYPE_DTEL_FLOW_SAMPLE_PERCENT) + .build() + ); + flowWLTable.setDescription("Dataplane Telemetry Flow Watchlist table"); + + dropWLTable.validateAddStage(ACL_STAGE_INGRESS); + dropWLTable.validateAddType(builder + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_SWITCH) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL)) + .withAction(SAI_ACL_ACTION_TYPE_DTEL_DROP_REPORT_ENABLE) + .withAction(SAI_ACL_ACTION_TYPE_DTEL_TAIL_DROP_REPORT_ENABLE) + .build() + ); + dropWLTable.setDescription("Dataplane Telemetry Drop Watchlist table"); - return SAI_STATUS_SUCCESS; + addAclTable(flowWLTable); + addAclTable(dropWLTable); } -sai_status_t AclOrch::deleteDTelWatchListTables() +void AclOrch::deleteDTelWatchListTables() { SWSS_LOG_ENTER(); - AclTable flowWLTable(this), dropWLTable(this); - sai_object_id_t table_oid; - string table_id = TABLE_TYPE_DTEL_FLOW_WATCHLIST; - - sai_status_t status; - - table_oid = getTableById(table_id); - - if (table_oid == SAI_NULL_OBJECT_ID) - { - SWSS_LOG_INFO("Failed to find ACL table %s", table_id.c_str()); - return SAI_STATUS_FAILURE; - } - - status = sai_acl_api->remove_acl_table(table_oid); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to delete table %s", table_id.c_str()); - if (handleSaiRemoveStatus(SAI_API_ACL, status) != task_success) - { - return status; - } - } - - gCrmOrch->decCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, SAI_ACL_STAGE_INGRESS, SAI_ACL_BIND_POINT_TYPE_SWITCH, table_oid); - m_AclTables.erase(table_oid); - - table_id = TABLE_TYPE_DTEL_DROP_WATCHLIST; - - table_oid = getTableById(table_id); - - if (table_oid == SAI_NULL_OBJECT_ID) - { - SWSS_LOG_INFO("Failed to find ACL table %s", table_id.c_str()); - return SAI_STATUS_FAILURE; - } - - status = sai_acl_api->remove_acl_table(table_oid); - if (status != SAI_STATUS_SUCCESS) - { - SWSS_LOG_ERROR("Failed to delete table %s", table_id.c_str()); - if (handleSaiRemoveStatus(SAI_API_ACL, status) != task_success) - { - return status; - } - } - - gCrmOrch->decCrmAclUsedCounter(CrmResourceType::CRM_ACL_TABLE, SAI_ACL_STAGE_INGRESS, SAI_ACL_BIND_POINT_TYPE_SWITCH, table_oid); - m_AclTables.erase(table_oid); - - return SAI_STATUS_SUCCESS; + removeAclTable(TABLE_TYPE_DTEL_FLOW_WATCHLIST); + removeAclTable(TABLE_TYPE_DTEL_DROP_WATCHLIST); } void AclOrch::registerFlexCounter(const AclRule& rule) diff --git a/orchagent/aclorch.h b/orchagent/aclorch.h index 9b1df1857016..9e6db3919c5d 100644 --- a/orchagent/aclorch.h +++ b/orchagent/aclorch.h @@ -50,6 +50,9 @@ #define MATCH_INNER_L4_SRC_PORT "INNER_L4_SRC_PORT" #define MATCH_INNER_L4_DST_PORT "INNER_L4_DST_PORT" +#define BIND_POINT_TYPE_PORT "PORT" +#define BIND_POINT_TYPE_PORTCHANNEL "PORTCHANNEL" + #define ACTION_PACKET_ACTION "PACKET_ACTION" #define ACTION_REDIRECT_ACTION "REDIRECT_ACTION" #define ACTION_DO_NOT_NAT_ACTION "DO_NOT_NAT_ACTION" @@ -94,15 +97,100 @@ #define ACL_COUNTER_FLEX_COUNTER_GROUP "ACL_STAT_COUNTER" +struct AclActionCapabilities +{ + set actionList; + bool isActionListMandatoryOnTableCreation {false}; +}; + typedef map acl_rule_attr_lookup_t; typedef map acl_range_type_lookup_t; +typedef map acl_bind_point_type_lookup_t; typedef map acl_ip_type_lookup_t; typedef map acl_dtel_flow_op_type_lookup_t; typedef map acl_packet_action_lookup_t; typedef tuple acl_range_properties_t; -typedef map> acl_capabilities_t; +typedef map acl_capabilities_t; typedef map> acl_action_enum_values_capabilities_t; +class AclRule; + +class AclTableMatchInterface +{ +public: + AclTableMatchInterface(sai_acl_table_attr_t matchField); + + sai_acl_table_attr_t getId() const; + virtual sai_attribute_t toSaiAttribute() = 0; + virtual bool validateAclRuleMatch(const AclRule& rule) const = 0; +private: + sai_acl_table_attr_t m_matchField; +}; + +class AclTableMatch: public AclTableMatchInterface +{ +public: + AclTableMatch(sai_acl_table_attr_t matchField); + + sai_attribute_t toSaiAttribute() override; + bool validateAclRuleMatch(const AclRule& rule) const override; +}; + +class AclTableRangeMatch: public AclTableMatchInterface +{ +public: + AclTableRangeMatch(set rangeTypes); + + sai_attribute_t toSaiAttribute() override; + bool validateAclRuleMatch(const AclRule& rule) const override; + +private: + vector m_rangeList; +}; +class AclTableType +{ +public: + string getName() const; + const set& getBindPointTypes() const; + const map>& getMatches() const; + const set& getRangeTypes() const; + const set& getActions() const; + +private: + friend class AclTableTypeBuilder; + + string m_name; + set m_bpointTypes; + map> m_matches; + set m_aclAcitons; +}; + +class AclTableTypeBuilder +{ +public: + AclTableTypeBuilder& withName(string name); + AclTableTypeBuilder& withBindPointType(sai_acl_bind_point_type_t bpointType); + AclTableTypeBuilder& withMatch(shared_ptr match); + AclTableTypeBuilder& withAction(sai_acl_action_type_t action); + AclTableType build(); + +private: + AclTableType m_tableType; +}; + +class AclTableTypeParser +{ +public: + bool parse( + const string& key, + const vector& fieldValues, + AclTableTypeBuilder& builder); +private: + bool parseAclTableTypeMatches(const string& value, AclTableTypeBuilder& builder); + bool parseAclTableTypeActions(const string& value, AclTableTypeBuilder& builder); + bool parseAclTableTypeBindPointTypes(const string& value, AclTableTypeBuilder& builder); +}; + class AclOrch; struct AclRangeConfig @@ -134,10 +222,12 @@ class AclRange static map m_ranges; }; +class AclTable; + class AclRule { public: - AclRule(AclOrch *pAclOrch, string rule, string table, acl_table_type_t type, bool createCounter = true); + AclRule(AclOrch *pAclOrch, string rule, string table, bool createCounter = true); virtual bool validateAddPriority(string attr_name, string attr_value); virtual bool validateAddMatch(string attr_name, string attr_value); virtual bool validateAddAction(string attr_name, string attr_value) = 0; @@ -158,34 +248,15 @@ class AclRule virtual bool enableCounter(); virtual bool disableCounter(); - sai_object_id_t getOid() const - { - return m_ruleOid; - } - - string getId() const - { - return m_id; - } - - string getTableId() const - { - return m_tableId; - } - - sai_object_id_t getCounterOid() const - { - return m_counterOid; - } - + string getId() const; + string getTableId() const; + sai_object_id_t getOid() const; + sai_object_id_t getCounterOid() const; + bool hasCounter() const; vector getInPorts() const; - bool hasCounter() const - { - return getCounterOid() != SAI_NULL_OBJECT_ID; - } - - static shared_ptr makeShared(acl_table_type_t type, AclOrch *acl, MirrorOrch *mirror, DTelOrch *dtel, const string& rule, const string& table, const KeyOpFieldsValuesTuple&); + const vector& getRangeConfig() const; + static shared_ptr makeShared(AclOrch *acl, MirrorOrch *mirror, DTelOrch *dtel, const string& rule, const string& table, const KeyOpFieldsValuesTuple&); virtual ~AclRule() {} protected: @@ -214,9 +285,7 @@ class AclRule static sai_uint32_t m_maxPriority; AclOrch *m_pAclOrch; string m_id; - string m_tableId; - acl_table_type_t m_tableType; - sai_object_id_t m_tableOid; + const AclTable* m_pTable {nullptr}; sai_object_id_t m_ruleOid; sai_object_id_t m_counterOid; uint32_t m_priority; @@ -232,13 +301,12 @@ class AclRule bool m_createCounter; }; -class AclRuleL3: public AclRule +class AclRulePacket: public AclRule { public: - AclRuleL3(AclOrch *m_pAclOrch, string rule, string table, acl_table_type_t type, bool createCounter = true); + AclRulePacket(AclOrch *m_pAclOrch, string rule, string table, bool createCounter = true); bool validateAddAction(string attr_name, string attr_value); - bool validateAddMatch(string attr_name, string attr_value); bool validate(); void onUpdate(SubjectType, void *) override; @@ -246,33 +314,11 @@ class AclRuleL3: public AclRule sai_object_id_t getRedirectObjectId(const string& redirect_param); }; -class AclRuleL3V6: public AclRuleL3 -{ -public: - AclRuleL3V6(AclOrch *m_pAclOrch, string rule, string table, acl_table_type_t type); - bool validateAddMatch(string attr_name, string attr_value); -}; - -class AclRulePfcwd: public AclRuleL3 -{ -public: - AclRulePfcwd(AclOrch *m_pAclOrch, string rule, string table, acl_table_type_t type, bool createCounter = false); - bool validateAddMatch(string attr_name, string attr_value); -}; - -class AclRuleMux: public AclRuleL3 -{ -public: - AclRuleMux(AclOrch *m_pAclOrch, string rule, string table, acl_table_type_t type, bool createCounter = false); - bool validateAddMatch(string attr_name, string attr_value); -}; - class AclRuleMirror: public AclRule { public: - AclRuleMirror(AclOrch *m_pAclOrch, MirrorOrch *m_pMirrorOrch, string rule, string table, acl_table_type_t type); + AclRuleMirror(AclOrch *m_pAclOrch, MirrorOrch *m_pMirrorOrch, string rule, string table); bool validateAddAction(string attr_name, string attr_value); - bool validateAddMatch(string attr_name, string attr_value); bool validate(); bool createRule(); bool removeRule(); @@ -291,7 +337,7 @@ class AclRuleMirror: public AclRule class AclRuleDTelFlowWatchListEntry: public AclRule { public: - AclRuleDTelFlowWatchListEntry(AclOrch *m_pAclOrch, DTelOrch *m_pDTelOrch, string rule, string table, acl_table_type_t type); + AclRuleDTelFlowWatchListEntry(AclOrch *m_pAclOrch, DTelOrch *m_pDTelOrch, string rule, string table); bool validateAddAction(string attr_name, string attr_value); bool validate(); bool createRule(); @@ -312,7 +358,7 @@ class AclRuleDTelFlowWatchListEntry: public AclRule class AclRuleDTelDropWatchListEntry: public AclRule { public: - AclRuleDTelDropWatchListEntry(AclOrch *m_pAclOrch, DTelOrch *m_pDTelOrch, string rule, string table, acl_table_type_t type); + AclRuleDTelDropWatchListEntry(AclOrch *m_pAclOrch, DTelOrch *m_pDTelOrch, string rule, string table); bool validateAddAction(string attr_name, string attr_value); bool validate(); void onUpdate(SubjectType, void *) override; @@ -320,14 +366,6 @@ class AclRuleDTelDropWatchListEntry: public AclRule DTelOrch *m_pDTelOrch; }; -class AclRuleMclag: public AclRuleL3 -{ -public: - AclRuleMclag(AclOrch *m_pAclOrch, string rule, string table, acl_table_type_t type, bool createCounter = false); - bool validateAddMatch(string attr_name, string attr_value); - bool validate(); -}; - class AclTable { public: @@ -337,18 +375,23 @@ class AclTable AclTable() = default; ~AclTable() = default; - sai_object_id_t getOid() { return m_oid; } - string getId() { return id; } + sai_object_id_t getOid() const { return m_oid; } + string getId() const { return id; } void setDescription(const string &value) { description = value; } const string& getDescription() const { return description; } - bool validateAddType(const acl_table_type_t &value); + bool validateAddType(const AclTableType &tableType); bool validateAddStage(const acl_stage_type_t &value); bool validateAddPorts(const unordered_set &value); bool validate(); bool create(); + // validate AclRule match attribute against rule and table configuration + bool validateAclRuleMatch(sai_acl_entry_attr_t matchId, const AclRule& rule) const; + // validate AclRule action attribute against rule and table configuration + bool validateAclRuleAction(sai_acl_entry_attr_t actionId, const AclRule& rule) const; + // Bind the ACL table to a port which is already linked bool bind(sai_object_id_t portOid); // Unbind the ACL table to a port which is already linked @@ -376,7 +419,7 @@ class AclTable string id; string description; - acl_table_type_t type = ACL_TABLE_UNKNOWN; + AclTableType type; acl_stage_type_t stage = ACL_STAGE_INGRESS; // Map port oid to group member oid @@ -397,6 +440,7 @@ class AclOrch : public Orch, public Observer { public: AclOrch(vector& connectors, + DBConnector *m_stateDb, SwitchOrch *m_switchOrch, PortsOrch *portOrch, MirrorOrch *mirrorOrch, @@ -408,6 +452,7 @@ class AclOrch : public Orch, public Observer sai_object_id_t getTableById(string table_id); const AclTable* getTableByOid(sai_object_id_t oid) const; + const AclTableType* getAclTableType(const std::string& tableTypeName) const; static swss::Table& getCountersTable() { @@ -422,6 +467,8 @@ class AclOrch : public Orch, public Observer bool addAclTable(AclTable &aclTable); bool removeAclTable(string table_id); + bool addAclTableType(const AclTableType& tableType); + bool removeAclTableType(const string& tableTypeName); bool updateAclTable(AclTable ¤tTable, AclTable &newTable); bool updateAclTable(string table_id, AclTable &table); bool addAclRule(shared_ptr aclRule, string table_id); @@ -432,14 +479,15 @@ class AclOrch : public Orch, public Observer AclRule* getAclRule(string table_id, string rule_id); bool isCombinedMirrorV6Table(); - bool isAclMirrorTableSupported(acl_table_type_t type) const; + bool isAclMirrorV6Supported() const; + bool isAclMirrorV4Supported() const; + bool isAclMirrorTableSupported(string type) const; + bool isAclActionListMandatoryOnTableCreation(acl_stage_type_t stage) const; bool isAclActionSupported(acl_stage_type_t stage, sai_acl_action_type_t action) const; bool isAclActionEnumValueSupported(sai_acl_action_type_t action, sai_acl_action_parameter_t param) const; bool m_isCombinedMirrorV6Table = true; - map m_mirrorTableCapabilities; - - static sai_acl_action_type_t getAclActionFromAclEntry(sai_acl_entry_attr_t attr); + map m_mirrorTableCapabilities; // Get the OID for the ACL bind point for a given port static bool getAclBindPortId(Port& port, sai_object_id_t& port_id); @@ -455,7 +503,9 @@ class AclOrch : public Orch, public Observer void doTask(Consumer &consumer); void doAclTableTask(Consumer &consumer); void doAclRuleTask(Consumer &consumer); + void doAclTableTypeTask(Consumer &consumer); void init(vector& connectors, PortsOrch *portOrch, MirrorOrch *mirrorOrch, NeighOrch *neighOrch, RouteOrch *routeOrch); + void initDefaultTableTypes(); void queryMirrorTableCapability(); void queryAclActionCapability(); @@ -473,10 +523,10 @@ class AclOrch : public Orch, public Observer sai_status_t bindAclTable(AclTable &aclTable, bool bind = true); sai_status_t deleteUnbindAclTable(sai_object_id_t table_oid); - bool isAclTableTypeUpdated(acl_table_type_t table_type, AclTable &aclTable); - bool processAclTableType(string type, acl_table_type_t &table_type); + bool isAclTableTypeUpdated(string table_type, AclTable &aclTable); bool isAclTableStageUpdated(acl_stage_type_t acl_stage, AclTable &aclTable); bool processAclTableStage(string stage, acl_stage_type_t &acl_stage); + bool processAclTableType(string type, string &out_table_type); bool processAclTablePorts(string portList, AclTable &aclTable); bool validateAclTable(AclTable &aclTable); bool updateAclTablePorts(AclTable &newTable, AclTable &curTable); @@ -484,8 +534,8 @@ class AclOrch : public Orch, public Observer AclTable &curT, set &addSet, set &delSet); - sai_status_t createDTelWatchListTables(); - sai_status_t deleteDTelWatchListTables(); + void createDTelWatchListTables(); + void deleteDTelWatchListTables(); void registerFlexCounter(const AclRule& rule); void deregisterFlexCounter(const AclRule& rule); @@ -494,10 +544,13 @@ class AclOrch : public Orch, public Observer map m_AclTables; // TODO: Move all ACL tables into one map: name -> instance map m_ctrlAclTables; + map m_AclTableTypes; static DBConnector m_countersDb; static Table m_countersTable; + Table m_aclStageCapabilityTable; + map m_mirrorTableId; map m_mirrorV6TableId; diff --git a/orchagent/acltable.h b/orchagent/acltable.h index 44d6ea4dbf81..081170984f90 100644 --- a/orchagent/acltable.h +++ b/orchagent/acltable.h @@ -15,6 +15,10 @@ extern "C" { #define ACL_TABLE_PORTS "PORTS" #define ACL_TABLE_SERVICES "SERVICES" +#define ACL_TABLE_TYPE_MATCHES "MATCHES" +#define ACL_TABLE_TYPE_BPOINT_TYPES "BIND_POINTS" +#define ACL_TABLE_TYPE_ACTIONS "ACTIONS" + #define STAGE_INGRESS "INGRESS" #define STAGE_EGRESS "EGRESS" @@ -39,23 +43,3 @@ typedef enum } acl_stage_type_t; typedef std::unordered_map acl_stage_type_lookup_t; - -typedef enum -{ - ACL_TABLE_UNKNOWN, - ACL_TABLE_L3, - ACL_TABLE_L3V6, - ACL_TABLE_MIRROR, - ACL_TABLE_MIRRORV6, - ACL_TABLE_MIRROR_DSCP, - ACL_TABLE_PFCWD, - ACL_TABLE_CTRLPLANE, - ACL_TABLE_DTEL_FLOW_WATCHLIST, - ACL_TABLE_DTEL_DROP_WATCHLIST, - ACL_TABLE_MCLAG, - ACL_TABLE_MUX, - ACL_TABLE_DROP, - ACL_TABLE_PBH -} acl_table_type_t; - -typedef std::unordered_map acl_table_type_lookup_t; diff --git a/orchagent/muxorch.cpp b/orchagent/muxorch.cpp index f7af9f1f5c2f..5b7b0570a579 100644 --- a/orchagent/muxorch.cpp +++ b/orchagent/muxorch.cpp @@ -709,7 +709,6 @@ MuxAclHandler::MuxAclHandler(sai_object_id_t port, string alias) SWSS_LOG_ENTER(); // There is one handler instance per MUX port - acl_table_type_t table_type = ACL_TABLE_DROP; string table_name = MUX_ACL_TABLE_NAME; string rule_name = MUX_ACL_RULE_NAME; @@ -723,8 +722,8 @@ MuxAclHandler::MuxAclHandler(sai_object_id_t port, string alias) // First time handling of Mux Table, create ACL table, and bind createMuxAclTable(port, table_name); - shared_ptr newRule = - make_shared(gAclOrch, rule_name, table_name, table_type); + shared_ptr newRule = + make_shared(gAclOrch, rule_name, table_name); createMuxAclRule(newRule, table_name); } else @@ -734,8 +733,8 @@ MuxAclHandler::MuxAclHandler(sai_object_id_t port, string alias) AclRule* rule = gAclOrch->getAclRule(table_name, rule_name); if (rule == nullptr) { - shared_ptr newRule = - make_shared(gAclOrch, rule_name, table_name, table_type); + shared_ptr newRule = + make_shared(gAclOrch, rule_name, table_name); createMuxAclRule(newRule, table_name); } else @@ -776,7 +775,7 @@ void MuxAclHandler::createMuxAclTable(sai_object_id_t port, string strTable) auto inserted = acl_table_.emplace(piecewise_construct, std::forward_as_tuple(strTable), - std::forward_as_tuple()); + std::forward_as_tuple(gAclOrch, strTable)); assert(inserted.second); @@ -791,14 +790,15 @@ void MuxAclHandler::createMuxAclTable(sai_object_id_t port, string strTable) return; } - acl_table.type = ACL_TABLE_DROP; - acl_table.id = strTable; + auto dropType = gAclOrch->getAclTableType(TABLE_TYPE_DROP); + assert(dropType); + acl_table.validateAddType(*dropType); acl_table.stage = ACL_STAGE_INGRESS; gAclOrch->addAclTable(acl_table); bindAllPorts(acl_table); } -void MuxAclHandler::createMuxAclRule(shared_ptr rule, string strTable) +void MuxAclHandler::createMuxAclRule(shared_ptr rule, string strTable) { SWSS_LOG_ENTER(); diff --git a/orchagent/muxorch.h b/orchagent/muxorch.h index fa8b0588301f..6e4f70408c5f 100644 --- a/orchagent/muxorch.h +++ b/orchagent/muxorch.h @@ -43,7 +43,7 @@ class MuxAclHandler private: void createMuxAclTable(sai_object_id_t port, string strTable); - void createMuxAclRule(shared_ptr rule, string strTable); + void createMuxAclRule(shared_ptr rule, string strTable); void bindAllPorts(AclTable &acl_table); // class shared dict: ACL table name -> ACL table diff --git a/orchagent/orchdaemon.cpp b/orchagent/orchdaemon.cpp index 9b533676ceb5..52beb0fd10d7 100644 --- a/orchagent/orchdaemon.cpp +++ b/orchagent/orchdaemon.cpp @@ -229,15 +229,19 @@ bool OrchDaemon::init() gMirrorOrch = new MirrorOrch(stateDbMirrorSession, confDbMirrorSession, gPortsOrch, gRouteOrch, gNeighOrch, gFdbOrch, policer_orch); TableConnector confDbAclTable(m_configDb, CFG_ACL_TABLE_TABLE_NAME); + TableConnector confDbAclTableType(m_configDb, CFG_ACL_TABLE_TYPE_TABLE_NAME); TableConnector confDbAclRuleTable(m_configDb, CFG_ACL_RULE_TABLE_NAME); TableConnector appDbAclTable(m_applDb, APP_ACL_TABLE_TABLE_NAME); + TableConnector appDbAclTableType(m_applDb, APP_ACL_TABLE_TYPE_TABLE_NAME); TableConnector appDbAclRuleTable(m_applDb, APP_ACL_RULE_TABLE_NAME); vector acl_table_connectors = { + confDbAclTableType, confDbAclTable, confDbAclRuleTable, appDbAclTable, - appDbAclRuleTable + appDbAclRuleTable, + appDbAclTableType, }; vector dtel_tables = { @@ -350,7 +354,9 @@ bool OrchDaemon::init() dtel_orch = new DTelOrch(m_configDb, dtel_tables, gPortsOrch); m_orchList.push_back(dtel_orch); } - gAclOrch = new AclOrch(acl_table_connectors, gSwitchOrch, gPortsOrch, gMirrorOrch, gNeighOrch, gRouteOrch, dtel_orch); + + gAclOrch = new AclOrch(acl_table_connectors, m_stateDb, + gSwitchOrch, gPortsOrch, gMirrorOrch, gNeighOrch, gRouteOrch, dtel_orch); vector mlag_tables = { { CFG_MCLAG_TABLE_NAME }, diff --git a/orchagent/pbh/pbhrule.cpp b/orchagent/pbh/pbhrule.cpp index d4e2218cf09d..7d35f4bb8fdf 100644 --- a/orchagent/pbh/pbhrule.cpp +++ b/orchagent/pbh/pbhrule.cpp @@ -3,7 +3,7 @@ #include "pbhrule.h" AclRulePbh::AclRulePbh(AclOrch *pAclOrch, string rule, string table, bool createCounter) : - AclRule(pAclOrch, rule, table, ACL_TABLE_PBH, createCounter) + AclRule(pAclOrch, rule, table, createCounter) { } diff --git a/orchagent/pbhorch.cpp b/orchagent/pbhorch.cpp index 3d0b43ce010e..83a1e80bd043 100644 --- a/orchagent/pbhorch.cpp +++ b/orchagent/pbhorch.cpp @@ -180,7 +180,18 @@ bool PbhOrch::createPbhTable(const PbhTable &table) AclTable pbhTable(this->aclOrch, table.name); - if (!pbhTable.validateAddType(acl_table_type_t::ACL_TABLE_PBH)) + static const auto pbhTableType = AclTableTypeBuilder() + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .withMatch(std::make_shared(SAI_ACL_TABLE_ATTR_FIELD_GRE_KEY)) + .withMatch(std::make_shared(SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE)) + .withMatch(std::make_shared(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL)) + .withMatch(std::make_shared(SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER)) + .withMatch(std::make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(std::make_shared(SAI_ACL_TABLE_ATTR_FIELD_INNER_ETHER_TYPE)) + .build(); + + if (!pbhTable.validateAddType(pbhTableType)) { SWSS_LOG_ERROR("Failed to configure PBH table(%s) type", table.key.c_str()); return false; diff --git a/orchagent/pfcactionhandler.cpp b/orchagent/pfcactionhandler.cpp index 0a24b1ba0122..e44521f849f9 100644 --- a/orchagent/pfcactionhandler.cpp +++ b/orchagent/pfcactionhandler.cpp @@ -301,20 +301,20 @@ PfcWdAclHandler::PfcWdAclHandler(sai_object_id_t port, sai_object_id_t queue, { SWSS_LOG_ENTER(); - acl_table_type_t table_type; + string table_type; string queuestr = to_string(queueId); m_strRule = "Rule_PfcWdAclHandler_" + queuestr; // Ingress table/rule creation - table_type = ACL_TABLE_DROP; + table_type = TABLE_TYPE_DROP; m_strIngressTable = INGRESS_TABLE_DROP; auto found = m_aclTables.find(m_strIngressTable); if (found == m_aclTables.end()) { // First time of handling PFC for this queue, create ACL table, and bind createPfcAclTable(port, m_strIngressTable, true); - shared_ptr newRule = make_shared(gAclOrch, m_strRule, m_strIngressTable, table_type); + shared_ptr newRule = make_shared(gAclOrch, m_strRule, m_strIngressTable); createPfcAclRule(newRule, queueId, m_strIngressTable, port); } else @@ -322,7 +322,7 @@ PfcWdAclHandler::PfcWdAclHandler(sai_object_id_t port, sai_object_id_t queue, AclRule* rule = gAclOrch->getAclRule(m_strIngressTable, m_strRule); if (rule == nullptr) { - shared_ptr newRule = make_shared(gAclOrch, m_strRule, m_strIngressTable, table_type); + shared_ptr newRule = make_shared(gAclOrch, m_strRule, m_strIngressTable); createPfcAclRule(newRule, queueId, m_strIngressTable, port); } else @@ -332,14 +332,14 @@ PfcWdAclHandler::PfcWdAclHandler(sai_object_id_t port, sai_object_id_t queue, } // Egress table/rule creation - table_type = ACL_TABLE_PFCWD; + table_type = TABLE_TYPE_PFCWD; m_strEgressTable = "EgressTable_PfcWdAclHandler_" + queuestr; found = m_aclTables.find(m_strEgressTable); if (found == m_aclTables.end()) { // First time of handling PFC for this queue, create ACL table, and bind createPfcAclTable(port, m_strEgressTable, false); - shared_ptr newRule = make_shared(gAclOrch, m_strRule, m_strEgressTable, table_type); + shared_ptr newRule = make_shared(gAclOrch, m_strRule, m_strEgressTable); createPfcAclRule(newRule, queueId, m_strEgressTable, port); } else @@ -392,7 +392,7 @@ void PfcWdAclHandler::createPfcAclTable(sai_object_id_t port, string strTable, b auto inserted = m_aclTables.emplace(piecewise_construct, std::forward_as_tuple(strTable), - std::forward_as_tuple()); + std::forward_as_tuple(gAclOrch, strTable)); assert(inserted.second); @@ -408,23 +408,26 @@ void PfcWdAclHandler::createPfcAclTable(sai_object_id_t port, string strTable, b } aclTable.link(port); - aclTable.id = strTable; if (ingress) { - aclTable.type = ACL_TABLE_DROP; + auto dropType = gAclOrch->getAclTableType(TABLE_TYPE_DROP); + assert(dropType); + aclTable.validateAddType(*dropType); aclTable.stage = ACL_STAGE_INGRESS; } else { - aclTable.type = ACL_TABLE_PFCWD; + auto pfcwdType = gAclOrch->getAclTableType(TABLE_TYPE_PFCWD); + assert(pfcwdType); + aclTable.validateAddType(*pfcwdType); aclTable.stage = ACL_STAGE_EGRESS; } gAclOrch->addAclTable(aclTable); } -void PfcWdAclHandler::createPfcAclRule(shared_ptr rule, uint8_t queueId, string strTable, sai_object_id_t portOid) +void PfcWdAclHandler::createPfcAclRule(shared_ptr rule, uint8_t queueId, string strTable, sai_object_id_t portOid) { SWSS_LOG_ENTER(); diff --git a/orchagent/pfcactionhandler.h b/orchagent/pfcactionhandler.h index 381f9bdca84c..23cabaee1010 100644 --- a/orchagent/pfcactionhandler.h +++ b/orchagent/pfcactionhandler.h @@ -111,7 +111,7 @@ class PfcWdAclHandler: public PfcWdLossyHandler string m_strEgressTable; string m_strRule; void createPfcAclTable(sai_object_id_t port, string strTable, bool ingress); - void createPfcAclRule(shared_ptr rule, uint8_t queueId, string strTable, sai_object_id_t port); + void createPfcAclRule(shared_ptr rule, uint8_t queueId, string strTable, sai_object_id_t port); void updatePfcAclRule(shared_ptr rule, uint8_t queueId, string strTable, vector port); }; diff --git a/orchagent/saihelper.h b/orchagent/saihelper.h index 450acf8b69fd..a0b2aa2facf0 100644 --- a/orchagent/saihelper.h +++ b/orchagent/saihelper.h @@ -4,6 +4,9 @@ #include +#define IS_ATTR_ID_IN_RANGE(attrId, objectType, attrPrefix) \ + ((attrId) >= SAI_ ## objectType ## _ATTR_ ## attrPrefix ## _START && (attrId) <= SAI_ ## objectType ## _ATTR_ ## attrPrefix ## _END) + void initSaiApi(); void initSaiRedis(const std::string &record_location, const std::string &record_filename); sai_status_t initSaiPhyApi(swss::gearbox_phy_t *phy); diff --git a/tests/dvslib/dvs_acl.py b/tests/dvslib/dvs_acl.py index dbf9791b5389..9111de7a8e04 100644 --- a/tests/dvslib/dvs_acl.py +++ b/tests/dvslib/dvs_acl.py @@ -6,6 +6,7 @@ class DVSAcl: """Manage ACL tables and rules on the virtual switch.""" CDB_ACL_TABLE_NAME = "ACL_TABLE" + CDB_ACL_TABLE_TYPE_NAME = "ACL_TABLE_TYPE" CDB_MIRROR_ACTION_LOOKUP = { "ingress": "MIRROR_INGRESS_ACTION", @@ -48,6 +49,26 @@ def __init__(self, asic_db, config_db, state_db, counters_db): self.state_db = state_db self.counters_db = counters_db + def create_acl_table_type( + self, + name: str, + matches: List[str], + bpoint_types: List[str] + ) -> None: + """Create a new ACL table type in Config DB. + + Args: + name: The name for the new ACL table type. + matches: A list of matches to use in ACL table. + bpoint_types: A list of bind point types to use in ACL table. + """ + table_type_attrs = { + "matches@": ",".join(matches), + "bind_points@": ",".join(bpoint_types) + } + + self.config_db.create_entry(self.CDB_ACL_TABLE_TYPE_NAME, name, table_type_attrs) + def create_acl_table( self, table_name: str, @@ -111,6 +132,14 @@ def remove_acl_table(self, table_name: str) -> None: """ self.config_db.delete_entry(self.CDB_ACL_TABLE_NAME, table_name) + def remove_acl_table_type(self, name: str) -> None: + """Remove an ACL table type from Config DB. + + Args: + name: The name of the ACL table type to delete. + """ + self.config_db.delete_entry(self.CDB_ACL_TABLE_TYPE_NAME, name) + def get_acl_table_ids(self, expected: int) -> List[str]: """Get all of the ACL table IDs in ASIC DB. diff --git a/tests/mock_tests/aclorch_ut.cpp b/tests/mock_tests/aclorch_ut.cpp index 4ffee617ad2f..c0d7399570c4 100644 --- a/tests/mock_tests/aclorch_ut.cpp +++ b/tests/mock_tests/aclorch_ut.cpp @@ -99,8 +99,25 @@ namespace aclorch_test TEST_F(AclTest, Create_L3_Acl_Table) { - AclTable acltable; - acltable.type = ACL_TABLE_L3; + AclTable acltable; /* this test shouldn't trigger a call to gAclOrch because it's nullptr */ + AclTableTypeBuilder builder; + auto l3TableType = builder + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_PORT) + .withBindPointType(SAI_ACL_BIND_POINT_TYPE_LAG) + .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_ACL_IP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_SRC_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_DST_IP)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMP_TYPE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_ICMP_CODE)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_SRC_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_L4_DST_PORT)) + .withMatch(make_shared(SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS)) + .withMatch(make_shared(set({SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE, SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE}))) + .build(); + acltable.type = l3TableType; auto res = createAclTable(acltable); ASSERT_TRUE(res->ret_val); @@ -139,7 +156,7 @@ namespace aclorch_test vector acl_table_connectors = { confDbAclTable, confDbAclRuleTable }; - m_aclOrch = new AclOrch(acl_table_connectors, switchOrch, portsOrch, mirrorOrch, + m_aclOrch = new AclOrch(acl_table_connectors, state_db, switchOrch, portsOrch, mirrorOrch, neighOrch, routeOrch); } @@ -153,6 +170,15 @@ namespace aclorch_test return m_aclOrch; } + void doAclTableTypeTask(const deque &entries) + { + auto consumer = unique_ptr(new Consumer( + new swss::ConsumerStateTable(config_db, CFG_ACL_TABLE_TYPE_TABLE_NAME, 1, 1), m_aclOrch, CFG_ACL_TABLE_TYPE_TABLE_NAME)); + + consumer->addToSync(entries); + static_cast(m_aclOrch)->doTask(*consumer); + } + void doAclTableTask(const deque &entries) { auto consumer = unique_ptr(new Consumer( @@ -176,6 +202,27 @@ namespace aclorch_test return m_aclOrch->getTableById(table_id); } + const AclRule* getAclRule(string tableName, string ruleName) + { + return m_aclOrch->getAclRule(tableName, ruleName); + } + + const AclTable* getTableByOid(sai_object_id_t oid) + { + return m_aclOrch->getTableByOid(oid); + } + + const AclTable* getAclTable(string tableName) + { + auto oid = m_aclOrch->getTableById(tableName); + return getTableByOid(oid); + } + + const AclTableType* getAclTableType(string tableTypeName) + { + return m_aclOrch->getAclTableType(tableTypeName); + } + const map &getAclTables() const { return Portal::AclOrchInternal::getAclTables(m_aclOrch); @@ -448,24 +495,22 @@ namespace aclorch_test fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_TCP_FLAGS", "true" }); fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_ACL_RANGE_TYPE", "2:SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE,SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE" }); - switch (acl_table.type) + if (acl_table.type.getName() == TABLE_TYPE_L3) { - case ACL_TABLE_L3: - fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true" }); - fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_SRC_IP", "true" }); - fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_DST_IP", "true" }); - fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL", "true" }); - break; - - case ACL_TABLE_L3V6: - fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6", "true" }); - fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6", "true" }); - fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER", "true" }); - break; - - default: - // We shouldn't get here. Will continue to add more test cases ...; - ; + fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true" }); + fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_SRC_IP", "true" }); + fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_DST_IP", "true" }); + fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_IP_PROTOCOL", "true" }); + } + else if (acl_table.type.getName() == TABLE_TYPE_L3V6) + { + fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_SRC_IPV6", "true" }); + fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_DST_IPV6", "true" }); + fields.push_back({ "SAI_ACL_TABLE_ATTR_FIELD_IPV6_NEXT_HEADER", "true" }); + } + else + { + // We shouldn't get here. Will continue to add more test cases ...; } if (ACL_STAGE_INGRESS == acl_table.stage) @@ -492,19 +537,17 @@ namespace aclorch_test fields.push_back({ "SAI_ACL_ENTRY_ATTR_ADMIN_STATE", "true" }); fields.push_back({ "SAI_ACL_ENTRY_ATTR_ACTION_COUNTER", counter_id }); - switch (acl_table.type) + if (acl_table.type.getName() == TABLE_TYPE_L3) { - case ACL_TABLE_L3: - fields.push_back({ "SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP", "1.2.3.4&mask:255.255.255.255" }); - break; - - case ACL_TABLE_L3V6: - fields.push_back({ "SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6", "::1.2.3.4&mask:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" }); - break; - - default: - // We shouldn't get here. Will continue to add more test cases ... - ; + fields.push_back({ "SAI_ACL_ENTRY_ATTR_FIELD_SRC_IP", "1.2.3.4&mask:255.255.255.255" }); + } + if (acl_table.type.getName() == TABLE_TYPE_L3V6) + { + fields.push_back({ "SAI_ACL_ENTRY_ATTR_FIELD_SRC_IPV6", "::1.2.3.4&mask:ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff" }); + } + else + { + // We shouldn't get here. Will continue to add more test cases ... } return shared_ptr(new SaiAttributeList(objecttype, fields, false)); @@ -569,13 +612,17 @@ namespace aclorch_test return true; } - bool validateAclTable(sai_object_id_t acl_table_oid, const AclTable &acl_table) + bool validateAclTable(sai_object_id_t acl_table_oid, const AclTable &acl_table, shared_ptr expAttrList = nullptr) { const sai_object_type_t objecttype = SAI_OBJECT_TYPE_ACL_TABLE; - auto exp_attrlist_2 = getAclTableAttributeList(objecttype, acl_table); + if (!expAttrList) + { + expAttrList = getAclTableAttributeList(objecttype, acl_table); + + } { - auto &exp_attrlist = *exp_attrlist_2; + auto &exp_attrlist = *expAttrList; vector act_attr; @@ -641,23 +688,16 @@ namespace aclorch_test auto const &resourceMap = Portal::CrmOrchInternal::getResourceMap(crmOrch); // Verify the ACL tables - uint32_t crmAclTableBindingCount = 0; + size_t crmAclTableBindingCount = 0; for (auto const &kv: resourceMap.at(CrmResourceType::CRM_ACL_TABLE).countersMap) { crmAclTableBindingCount += kv.second.usedCounter; } - uint32_t aclorchAclTableBindingCount = 0; + size_t aclorchAclTableBindingCount = 0; for (auto const &kv: Portal::AclOrchInternal::getAclTables(aclOrch)) { - if (kv.second.type == ACL_TABLE_PFCWD) - { - aclorchAclTableBindingCount += 1; // port binding only - } - else - { - aclorchAclTableBindingCount += 2; // port + LAG binding - } + aclorchAclTableBindingCount += kv.second.type.getBindPointTypes().size(); } if (crmAclTableBindingCount != aclorchAclTableBindingCount) @@ -770,21 +810,7 @@ namespace aclorch_test { if (fv.first == ACL_TABLE_TYPE) { - if (fv.second == TABLE_TYPE_L3) - { - if (acl_table.type != ACL_TABLE_L3) - { - return false; - } - } - else if (fv.second == TABLE_TYPE_L3V6) - { - if (acl_table.type != ACL_TABLE_L3V6) - { - return false; - } - } - else + if (acl_table.type.getName() != fv.second) { return false; } @@ -1336,6 +1362,279 @@ namespace aclorch_test ASSERT_EQ(tableIt, orch->getAclTables().end()); } + TEST_F(AclOrchTest, AclTableType_Configuration) + { + const string aclTableTypeName = "TEST_TYPE"; + const string aclTableName = "TEST_TABLE"; + const string aclRuleName = "TEST_RULE"; + + auto orch = createAclOrch(); + + auto tableKofvt = deque( + { + { + aclTableName, + SET_COMMAND, + { + { ACL_TABLE_DESCRIPTION, "Test table" }, + { ACL_TABLE_TYPE, aclTableTypeName}, + { ACL_TABLE_STAGE, STAGE_INGRESS }, + { ACL_TABLE_PORTS, "1,2" } + } + } + } + ); + + orch->doAclTableTask(tableKofvt); + + // Table not created without table type + ASSERT_FALSE(orch->getAclTable(aclTableName)); + + orch->doAclTableTypeTask( + deque( + { + { + aclTableTypeName, + SET_COMMAND, + { + { + ACL_TABLE_TYPE_MATCHES, + string(MATCH_SRC_IP) + comma + MATCH_ETHER_TYPE + comma + MATCH_L4_SRC_PORT_RANGE + }, + { + ACL_TABLE_TYPE_BPOINT_TYPES, + string(BIND_POINT_TYPE_PORT) + comma + BIND_POINT_TYPE_PORTCHANNEL + }, + } + } + } + ) + ); + + orch->doAclTableTask(tableKofvt); + + // Table is created now + ASSERT_TRUE(orch->getAclTable(aclTableName)); + + auto fvs = vector{ + { "SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST", "2:SAI_ACL_BIND_POINT_TYPE_PORT,SAI_ACL_BIND_POINT_TYPE_LAG" }, + { "SAI_ACL_TABLE_ATTR_FIELD_SRC_IP", "true" }, + { "SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true" }, + { "SAI_ACL_TABLE_ATTR_FIELD_ACL_RANGE_TYPE", "1:SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE" }, + }; + + ASSERT_TRUE(validateAclTable( + orch->getAclTable(aclTableName)->getOid(), + *orch->getAclTable(aclTableName), + make_shared(SAI_OBJECT_TYPE_ACL_TABLE, fvs, false)) + ); + + orch->doAclRuleTask( + deque( + { + { + aclTableName + "|" + aclRuleName, + SET_COMMAND, + { + { MATCH_SRC_IP, "1.1.1.1/32" }, + { MATCH_L4_DST_PORT_RANGE, "80..100" }, + { ACTION_PACKET_ACTION, PACKET_ACTION_DROP }, + } + } + } + ) + ); + + // L4_DST_PORT_RANGE is not in the table type + ASSERT_FALSE(orch->getAclRule(aclTableName, aclRuleName)); + + orch->doAclRuleTask( + deque( + { + { + aclTableName + "|" + aclRuleName, + SET_COMMAND, + { + { MATCH_SRC_IP, "1.1.1.1/32" }, + { MATCH_DST_IP, "2.2.2.2/32" }, + { ACTION_PACKET_ACTION, PACKET_ACTION_DROP }, + } + } + } + ) + ); + + // DST_IP is not in the table type + ASSERT_FALSE(orch->getAclRule(aclTableName, aclRuleName)); + + orch->doAclRuleTask( + deque( + { + { + aclTableName + "|" + aclRuleName, + SET_COMMAND, + { + { MATCH_SRC_IP, "1.1.1.1/32" }, + { ACTION_PACKET_ACTION, PACKET_ACTION_DROP }, + } + } + } + ) + ); + + // Now it is valid for this table. + ASSERT_TRUE(orch->getAclRule(aclTableName, aclRuleName)); + + orch->doAclRuleTask( + deque( + { + { + aclTableName + "|" + aclRuleName, + DEL_COMMAND, + {} + } + } + ) + ); + + ASSERT_FALSE(orch->getAclRule(aclTableName, aclRuleName)); + + orch->doAclTableTypeTask( + deque( + { + { + aclTableTypeName, + DEL_COMMAND, + {} + } + } + ) + ); + + // Table still exists + ASSERT_TRUE(orch->getAclTable(aclTableName)); + ASSERT_FALSE(orch->getAclTableType(aclTableTypeName)); + + orch->doAclTableTask( + deque( + { + { + aclTableName, + DEL_COMMAND, + {} + } + } + ) + ); + + // Table is removed + ASSERT_FALSE(orch->getAclTable(aclTableName)); + } + + TEST_F(AclOrchTest, AclTableType_ActionValidation) + { + const string aclTableTypeName = "TEST_TYPE"; + const string aclTableName = "TEST_TABLE"; + const string aclRuleName = "TEST_RULE"; + + auto orch = createAclOrch(); + + orch->doAclTableTypeTask( + deque( + { + { + aclTableTypeName, + SET_COMMAND, + { + { + ACL_TABLE_TYPE_MATCHES, + string(MATCH_ETHER_TYPE) + comma + MATCH_L4_SRC_PORT_RANGE + comma + MATCH_L4_DST_PORT_RANGE + }, + { + ACL_TABLE_TYPE_BPOINT_TYPES, + BIND_POINT_TYPE_PORTCHANNEL + }, + { + ACL_TABLE_TYPE_ACTIONS, + ACTION_MIRROR_INGRESS_ACTION + } + } + } + } + ) + ); + + orch->doAclTableTask( + deque( + { + { + aclTableName, + SET_COMMAND, + { + { ACL_TABLE_DESCRIPTION, "Test table" }, + { ACL_TABLE_TYPE, aclTableTypeName}, + { ACL_TABLE_STAGE, STAGE_INGRESS }, + { ACL_TABLE_PORTS, "1,2" } + } + } + } + ) + ); + + ASSERT_TRUE(orch->getAclTable(aclTableName)); + + auto fvs = vector{ + { "SAI_ACL_TABLE_ATTR_ACL_BIND_POINT_TYPE_LIST", "1:SAI_ACL_BIND_POINT_TYPE_LAG" }, + { "SAI_ACL_TABLE_ATTR_FIELD_ETHER_TYPE", "true" }, + { "SAI_ACL_TABLE_ATTR_FIELD_ACL_RANGE_TYPE", "2:SAI_ACL_RANGE_TYPE_L4_SRC_PORT_RANGE,SAI_ACL_RANGE_TYPE_L4_DST_PORT_RANGE" }, + { "SAI_ACL_TABLE_ATTR_ACL_ACTION_TYPE_LIST", "1:SAI_ACL_ACTION_TYPE_MIRROR_INGRESS" }, + }; + + ASSERT_TRUE(validateAclTable( + orch->getAclTable(aclTableName)->getOid(), + *orch->getAclTable(aclTableName), + make_shared(SAI_OBJECT_TYPE_ACL_TABLE, fvs, false)) + ); + + orch->doAclRuleTask( + deque( + { + { + aclTableName + "|" + aclRuleName, + SET_COMMAND, + { + { MATCH_ETHER_TYPE, "2048" }, + { ACTION_PACKET_ACTION, PACKET_ACTION_DROP }, + } + } + } + ) + ); + + // Packet action is not supported on this table + ASSERT_FALSE(orch->getAclRule(aclTableName, aclRuleName)); + + const auto testSessionName = "test_session"; + gMirrorOrch->createEntry(testSessionName, {}); + orch->doAclRuleTask( + deque( + { + { + aclTableName + "|" + aclRuleName, + SET_COMMAND, + { + { MATCH_ETHER_TYPE, "2048" }, + { ACTION_MIRROR_INGRESS_ACTION, testSessionName }, + } + } + } + ) + ); + + // Mirror action is supported on this table + ASSERT_TRUE(orch->getAclRule(aclTableName, aclRuleName)); + } + TEST_F(AclOrchTest, AclRuleUpdate) { string acl_table_id = "acl_table_1"; @@ -1362,11 +1661,11 @@ namespace aclorch_test auto it_table = acl_tables.find(acl_table_oid); ASSERT_NE(it_table, acl_tables.end()); - class AclRuleTest : public AclRuleL3 + class AclRuleTest : public AclRulePacket { public: AclRuleTest(AclOrch* orch, string rule, string table): - AclRuleL3(orch, rule, table, ACL_TABLE_L3, true) + AclRulePacket(orch, rule, table, true) {} void setCounterEnabled(bool enabled) diff --git a/tests/test_acl.py b/tests/test_acl.py index d4b317bf55cf..fb8aecb0ea80 100644 --- a/tests/test_acl.py +++ b/tests/test_acl.py @@ -10,6 +10,15 @@ L3V6_BIND_PORTS = ["Ethernet0", "Ethernet4", "Ethernet8"] L3V6_RULE_NAME = "L3V6_TEST_RULE" +MCLAG_TABLE_TYPE = "MCLAG" +MCLAG_TABLE_NAME = "MCLAG_TEST" +MCLAG_BIND_PORTS = ["Ethernet0", "Ethernet4", "Ethernet8", "Ethernet12"] +MCLAG_RULE_NAME = "MCLAG_TEST_RULE" + +MIRROR_TABLE_TYPE = "MIRROR" +MIRROR_TABLE_NAME = "MIRROR_TEST" +MIRROR_BIND_PORTS = ["Ethernet0", "Ethernet4", "Ethernet8", "Ethernet12"] +MIRROR_RULE_NAME = "MIRROR_TEST_RULE" class TestAcl: @pytest.yield_fixture @@ -32,6 +41,24 @@ def l3v6_acl_table(self, dvs_acl): dvs_acl.remove_acl_table(L3V6_TABLE_NAME) dvs_acl.verify_acl_table_count(0) + @pytest.yield_fixture + def mclag_acl_table(self, dvs_acl): + try: + dvs_acl.create_acl_table(MCLAG_TABLE_NAME, MCLAG_TABLE_TYPE, MCLAG_BIND_PORTS) + yield dvs_acl.get_acl_table_ids(1)[0] + finally: + dvs_acl.remove_acl_table(MCLAG_TABLE_NAME) + dvs_acl.verify_acl_table_count(0) + + @pytest.yield_fixture + def mirror_acl_table(self, dvs_acl): + try: + dvs_acl.create_acl_table(MIRROR_TABLE_NAME, MIRROR_TABLE_TYPE, MIRROR_BIND_PORTS) + yield dvs_acl.get_acl_table_ids(1)[0] + finally: + dvs_acl.remove_acl_table(MIRROR_TABLE_NAME) + dvs_acl.verify_acl_table_count(0) + @pytest.yield_fixture def setup_teardown_neighbor(self, dvs): try: @@ -133,42 +160,69 @@ def test_V6AclRuleNextHeaderAppendedForTCPFlags(self, dvs_acl, l3v6_acl_table): dvs_acl.remove_acl_rule(L3V6_TABLE_NAME, L3V6_RULE_NAME) dvs_acl.verify_no_acl_rules() - def test_AclRuleInOutPorts(self, dvs_acl, l3_acl_table): + def test_AclRuleInPorts(self, dvs_acl, mirror_acl_table): + """ + Verify IN_PORTS matches on ACL rule. + Using MIRROR table type for IN_PORTS matches. + """ config_qualifiers = { - "IN_PORTS": "Ethernet0,Ethernet4", - "OUT_PORTS": "Ethernet8,Ethernet12" + "IN_PORTS": "Ethernet8,Ethernet12", + } + + expected_sai_qualifiers = { + "SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS": dvs_acl.get_port_list_comparator(["Ethernet8", "Ethernet12"]) + } + + dvs_acl.create_acl_rule(MIRROR_TABLE_NAME, MIRROR_RULE_NAME, config_qualifiers) + dvs_acl.verify_acl_rule(expected_sai_qualifiers) + + dvs_acl.remove_acl_rule(MIRROR_TABLE_NAME, MIRROR_RULE_NAME) + dvs_acl.verify_no_acl_rules() + + def test_AclRuleOutPorts(self, dvs_acl, mclag_acl_table): + """ + Verify OUT_PORTS matches on ACL rule. + Using MCLAG table type for OUT_PORTS matches. + """ + config_qualifiers = { + "OUT_PORTS": "Ethernet8,Ethernet12", } expected_sai_qualifiers = { - "SAI_ACL_ENTRY_ATTR_FIELD_IN_PORTS": dvs_acl.get_port_list_comparator(["Ethernet0", "Ethernet4"]), "SAI_ACL_ENTRY_ATTR_FIELD_OUT_PORTS": dvs_acl.get_port_list_comparator(["Ethernet8", "Ethernet12"]) } - dvs_acl.create_acl_rule(L3_TABLE_NAME, L3_RULE_NAME, config_qualifiers) + dvs_acl.create_acl_rule(MCLAG_TABLE_NAME, MCLAG_RULE_NAME, config_qualifiers) dvs_acl.verify_acl_rule(expected_sai_qualifiers) - dvs_acl.remove_acl_rule(L3_TABLE_NAME, L3_RULE_NAME) + dvs_acl.remove_acl_rule(MCLAG_TABLE_NAME, MCLAG_RULE_NAME) dvs_acl.verify_no_acl_rules() - def test_AclRuleInPortsNonExistingInterface(self, dvs_acl, l3_acl_table): + def test_AclRuleInPortsNonExistingInterface(self, dvs_acl, mirror_acl_table): + """ + Using MIRROR table type as it has IN_PORTS matches. + """ config_qualifiers = { "IN_PORTS": "FOO_BAR_BAZ" } - dvs_acl.create_acl_rule(L3_TABLE_NAME, L3_RULE_NAME, config_qualifiers) + dvs_acl.create_acl_rule(MIRROR_TABLE_NAME, MIRROR_RULE_NAME, config_qualifiers) dvs_acl.verify_no_acl_rules() - dvs_acl.remove_acl_rule(L3_TABLE_NAME, L3_RULE_NAME) + dvs_acl.remove_acl_rule(MIRROR_TABLE_NAME, MIRROR_RULE_NAME) - def test_AclRuleOutPortsNonExistingInterface(self, dvs_acl, l3_acl_table): + def test_AclRuleOutPortsNonExistingInterface(self, dvs_acl, mclag_acl_table): + """ + Using MCLAG table type as it has OUT_PORTS matches. + """ config_qualifiers = { "OUT_PORTS": "FOO_BAR_BAZ" } - dvs_acl.create_acl_rule(L3_TABLE_NAME, L3_RULE_NAME, config_qualifiers) + dvs_acl.create_acl_rule(MCLAG_TABLE_NAME, MCLAG_RULE_NAME, config_qualifiers) dvs_acl.verify_no_acl_rules() - dvs_acl.remove_acl_rule(L3_TABLE_NAME, L3_RULE_NAME) + dvs_acl.remove_acl_rule(MCLAG_TABLE_NAME, MCLAG_RULE_NAME) def test_AclRuleVlanId(self, dvs_acl, l3_acl_table): config_qualifiers = {"VLAN_ID": "100"} @@ -550,15 +604,12 @@ def test_ValidateAclTableBindingCrmUtilization(self, dvs, dvs_acl): class TestAclRuleValidation: """Test class for cases that check if orchagent corectly validates ACL rules input.""" - SWITCH_CAPABILITY_TABLE = "SWITCH_CAPABILITY" + ACL_STAGE_CAPABILITY_TABLE_NAME = "ACL_STAGE_CAPABILITY_TABLE" + ACL_ACTION_LIST_FIELD_NAME = "action_list" def get_acl_actions_supported(self, dvs_acl, stage): - switch_id = dvs_acl.state_db.wait_for_n_keys(self.SWITCH_CAPABILITY_TABLE, 1)[0] - switch = dvs_acl.state_db.wait_for_entry(self.SWITCH_CAPABILITY_TABLE, switch_id) - - field = "ACL_ACTIONS|{}".format(stage.upper()) - - supported_actions = switch.get(field, None) + switch = dvs_acl.state_db.wait_for_entry(self.ACL_STAGE_CAPABILITY_TABLE_NAME, stage.upper()) + supported_actions = switch.get(self.ACL_ACTION_LIST_FIELD_NAME, None) if supported_actions: supported_actions = supported_actions.split(",") diff --git a/tests/test_acl_egress_table.py b/tests/test_acl_egress_table.py index f2b917ebc6fd..01800d6b206e 100644 --- a/tests/test_acl_egress_table.py +++ b/tests/test_acl_egress_table.py @@ -1,6 +1,19 @@ import pytest -TABLE_TYPE = "L3" +TABLE_TYPE = "CUSTOM_L3" +CUSTOM_TABLE_TYPE_MATCHES = [ + "L4_SRC_PORT_RANGE", + "L4_DST_PORT_RANGE", + "ETHER_TYPE", + "TUNNEL_VNI", + "TC", + "INNER_IP_PROTOCOL", + "INNER_ETHER_TYPE", + "INNER_L4_SRC_PORT", + "INNER_L4_DST_PORT", + "VLAN_ID" +] +CUSTOM_TABLE_TYPE_BPOINT_TYPES = ["PORT","PORTCHANNEL"] TABLE_NAME = "EGRESS_TEST" BIND_PORTS = ["Ethernet0", "Ethernet4"] RULE_NAME = "EGRESS_TEST_RULE" @@ -10,14 +23,17 @@ class TestEgressAclTable: @pytest.yield_fixture def egress_acl_table(self, dvs_acl): try: + dvs_acl.create_acl_table_type(TABLE_TYPE, CUSTOM_TABLE_TYPE_MATCHES, CUSTOM_TABLE_TYPE_BPOINT_TYPES) dvs_acl.create_acl_table(TABLE_NAME, TABLE_TYPE, BIND_PORTS, stage="egress") yield dvs_acl.get_acl_table_ids(1)[0] finally: dvs_acl.remove_acl_table(TABLE_NAME) + dvs_acl.remove_acl_table_type(TABLE_TYPE) dvs_acl.verify_acl_table_count(0) def test_EgressAclTableCreationDeletion(self, dvs_acl): try: + dvs_acl.create_acl_table_type(TABLE_TYPE, CUSTOM_TABLE_TYPE_MATCHES, CUSTOM_TABLE_TYPE_BPOINT_TYPES) dvs_acl.create_acl_table(TABLE_NAME, TABLE_TYPE, BIND_PORTS, stage="egress") acl_table_id = dvs_acl.get_acl_table_ids(1)[0] @@ -27,6 +43,7 @@ def test_EgressAclTableCreationDeletion(self, dvs_acl): dvs_acl.verify_acl_table_port_binding(acl_table_id, BIND_PORTS, 1, stage="egress") finally: dvs_acl.remove_acl_table(TABLE_NAME) + dvs_acl.remove_acl_table_type(TABLE_TYPE) dvs_acl.verify_acl_table_count(0) def test_EgressAclRuleL4SrcPortRange(self, dvs_acl, egress_acl_table): diff --git a/tests/test_mirror_ipv6_combined.py b/tests/test_mirror_ipv6_combined.py index cafa5eaf4719..e75f6af72dbd 100644 --- a/tests/test_mirror_ipv6_combined.py +++ b/tests/test_mirror_ipv6_combined.py @@ -473,85 +473,6 @@ def test_AclBindMirrorV6Reorder2(self, dvs, testlog): self.set_interface_status("Ethernet32", "down") - # Test case - create ACL rules associated with wrong table - # 0. predefine the VS platform: mellanox platform - # 1. create a mirror session - # 2. create the ipv4 ACL table - # 3. create the ipv6 ACL rule associated with ipv4 table - # 4. create the ipv6 ACL table - # 5. create the ipv4 ACL rule associated with ipv6 table - # 6. verify two rules are inserted successfully - def test_AclBindMirrorV6WrongConfig(self, dvs, testlog): - """ - This test verifies IPv6 rules cannot be inserted into MIRROR table - """ - self.setup_db(dvs) - - session = "MIRROR_SESSION" - acl_table = "MIRROR_TABLE" - acl_table_v6 = "MIRROR_TABLE_V6" - acl_rule_1 = "MIRROR_RULE_1" - acl_rule_2 = "MIRROR_RULE_2" - - # bring up port; assign ip; create neighbor; create route - self.set_interface_status("Ethernet32", "up") - self.add_ip_address("Ethernet32", "20.0.0.0/31") - self.add_neighbor("Ethernet32", "20.0.0.1", "02:04:06:08:10:12") - self.add_route(dvs, "4.4.4.4", "20.0.0.1") - - # create mirror session - self.create_mirror_session(session, "3.3.3.3", "4.4.4.4", "0x6558", "8", "100", "0") - assert self.get_mirror_session_state(session)["status"] == "active" - - # assert mirror session in asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - assert len(tbl.getKeys()) == 1 - mirror_session_oid = tbl.getKeys()[0] - - # create acl table ipv4 - self.create_acl_table(acl_table, ["Ethernet0", "Ethernet4"], "MIRROR") - - # create WRONG acl rule with IPv6 addresses - self.create_mirror_acl_ipv6_rule(acl_table, acl_rule_2, session) - - # assert acl rule is not created - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY") - rule_entries = [k for k in tbl.getKeys() if k not in dvs.asicdb.default_acl_entries] - assert len(rule_entries) == 0 - - # create acl table ipv6 - self.create_acl_table(acl_table_v6, ["Ethernet0", "Ethernet4"], "MIRRORV6") - - # create WRONG acl rule with IPv4 addresses - self.create_mirror_acl_ipv4_rule(acl_table_v6, acl_rule_1, session) - - # assert acl rules are created - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_ACL_ENTRY") - rule_entries = [k for k in tbl.getKeys() if k not in dvs.asicdb.default_acl_entries] - assert len(rule_entries) == 0 - - # remove acl rule - self.remove_mirror_acl_rule(acl_table, acl_rule_1) - self.remove_mirror_acl_rule(acl_table_v6, acl_rule_2) - - # remove acl table - self.remove_acl_table(acl_table) - self.remove_acl_table(acl_table_v6) - - # remove mirror session - self.remove_mirror_session(session) - - # assert no mirror session in asic database - tbl = swsscommon.Table(self.adb, "ASIC_STATE:SAI_OBJECT_TYPE_MIRROR_SESSION") - assert len(tbl.getKeys()) == 0 - - # remove route; remove neighbor; remove ip; bring down port - self.remove_route(dvs, "4.4.4.4") - self.remove_neighbor("Ethernet32", "20.0.0.1") - self.remove_ip_address("Ethernet32", "20.0.0.0/31") - self.set_interface_status("Ethernet32", "down") - - # Add Dummy always-pass test at end as workaroud # for issue when Flaky fail on final test it invokes module tear-down before retrying def test_nonflaky_dummy():